xref: /freebsd/sbin/ipf/ipfstat/ipfstat.c (revision 2e3f49888ec8851bafb22011533217487764fdb0)
1 
2 /*
3  * Copyright (C) 2012 by Darren Reed.
4  *
5  * See the IPFILTER.LICENCE file for details on licencing.
6  */
7 #include <sys/ioctl.h>
8 #include <ctype.h>
9 #include <fcntl.h>
10 # include <nlist.h>
11 #include <ctype.h>
12 #if defined(sun) && defined(__SVR4)
13 # include <stddef.h>
14 #endif
15 #include "ipf.h"
16 #include "netinet/ipl.h"
17 #if defined(STATETOP)
18 # if defined(sun) && defined(__SVR4)
19 #   include <sys/select.h>
20 # endif
21 # include <netinet/ip_var.h>
22 # include <netinet/tcp_fsm.h>
23 # include <ctype.h>
24 # include <signal.h>
25 # include <time.h>
26 # if SOLARIS || defined(__NetBSD__)
27 #  ifdef ERR
28 #   undef ERR
29 #  endif
30 #  include <curses.h>
31 # else /* SOLARIS */
32 #  include <ncurses.h>
33 # endif /* SOLARIS */
34 #endif /* STATETOP */
35 #include "kmem.h"
36 #if defined(__NetBSD__)
37 # include <paths.h>
38 #endif
39 
40 
41 
42 extern	char	*optarg;
43 extern	int	optind;
44 extern	int	opterr;
45 
46 #define	PRINTF	(void)printf
47 #define	FPRINTF	(void)fprintf
48 static	char	*filters[4] = { "ipfilter(in)", "ipfilter(out)",
49 				"ipacct(in)", "ipacct(out)" };
50 static	int	state_logging = -1;
51 static	wordtab_t	*state_fields = NULL;
52 
53 int	nohdrfields = 0;
54 int	opts = 0;
55 #ifdef	USE_INET6
56 int	use_inet4 = 0;
57 int	use_inet6 = 0;
58 #endif
59 int	live_kernel = 1;
60 int	state_fd = -1;
61 int	ipf_fd = -1;
62 int	auth_fd = -1;
63 int	nat_fd = -1;
64 frgroup_t *grtop = NULL;
65 frgroup_t *grtail = NULL;
66 
67 char *blockreasons[FRB_MAX_VALUE + 1] = {
68 	"packet blocked",
69 	"log rule failure",
70 	"pps rate exceeded",
71 	"jumbogram",
72 	"makefrip failed",
73 	"cannot add state",
74 	"IP ID update failed",
75 	"log-or-block failed",
76 	"decapsulate failure",
77 	"cannot create new auth entry",
78 	"packet queued for auth",
79 	"buffer coalesce failure",
80 	"buffer pullup failure",
81 	"auth feedback",
82 	"bad fragment",
83 	"IPv4 NAT failure",
84 	"IPv6 NAT failure"
85 };
86 
87 #ifdef STATETOP
88 #define	STSTRSIZE 	80
89 #define	STGROWSIZE	16
90 #define	HOSTNMLEN	40
91 
92 #define	STSORT_PR	0
93 #define	STSORT_PKTS	1
94 #define	STSORT_BYTES	2
95 #define	STSORT_TTL	3
96 #define	STSORT_SRCIP	4
97 #define	STSORT_SRCPT	5
98 #define	STSORT_DSTIP	6
99 #define	STSORT_DSTPT	7
100 #define	STSORT_MAX	STSORT_DSTPT
101 #define	STSORT_DEFAULT	STSORT_BYTES
102 
103 
104 typedef struct statetop {
105 	i6addr_t	st_src;
106 	i6addr_t	st_dst;
107 	u_short		st_sport;
108 	u_short 	st_dport;
109 	u_char		st_p;
110 	u_char		st_v;
111 	u_char		st_state[2];
112 	U_QUAD_T	st_pkts;
113 	U_QUAD_T	st_bytes;
114 	u_long		st_age;
115 } statetop_t;
116 #endif
117 
118 int		main(int, char *[]);
119 
120 static	int	fetchfrag(int, int, ipfr_t *);
121 static	void	showstats(friostat_t *, u_32_t);
122 static	void	showfrstates(ipfrstat_t *, u_long);
123 static	void	showlist(friostat_t *);
124 static	void	showstatestats(ips_stat_t *);
125 static	void	showipstates(ips_stat_t *, int *);
126 static	void	showauthstates(ipf_authstat_t *);
127 static	void	showtqtable_live(int);
128 static	void	showgroups(friostat_t *);
129 static	void	usage(char *);
130 static	int	state_matcharray(ipstate_t *, int *);
131 static	int	printlivelist(friostat_t *, int, int, frentry_t *,
132 				   char *, char *);
133 static	void	printdeadlist(friostat_t *, int, int, frentry_t *,
134 				   char *, char *);
135 static	void	printside(char *, ipf_statistics_t *);
136 static	void	parse_ipportstr(const char *, i6addr_t *, int *);
137 static	void	ipfstate_live(char *, friostat_t **, ips_stat_t **,
138 				   ipfrstat_t **, ipf_authstat_t **, u_32_t *);
139 static	void	ipfstate_dead(char *, friostat_t **, ips_stat_t **,
140 				   ipfrstat_t **, ipf_authstat_t **, u_32_t *);
141 static	ipstate_t *fetchstate(ipstate_t *, ipstate_t *);
142 #ifdef STATETOP
143 static	void	topipstates(i6addr_t, i6addr_t, int, int, int,
144 				 int, int, int, int *);
145 static	void	sig_break(int);
146 static	void	sig_resize(int);
147 static	char	*getip(int, i6addr_t *);
148 static	char	*ttl_to_string(long);
149 static	int	sort_p(const void *, const void *);
150 static	int	sort_pkts(const void *, const void *);
151 static	int	sort_bytes(const void *, const void *);
152 static	int	sort_ttl(const void *, const void *);
153 static	int	sort_srcip(const void *, const void *);
154 static	int	sort_srcpt(const void *, const void *);
155 static	int	sort_dstip(const void *, const void *);
156 static	int	sort_dstpt(const void *, const void *);
157 #endif
158 
159 
160 static void usage(char *name)
161 {
162 #ifdef  USE_INET6
163 	fprintf(stderr, "Usage: %s [-46aAdfghIilnoRsv]\n", name);
164 #else
165 	fprintf(stderr, "Usage: %s [-4aAdfghIilnoRsv]\n", name);
166 #endif
167 	fprintf(stderr, "       %s [-M corefile] [-N symbol-list]\n", name);
168 #ifdef	STATETOP
169 #ifdef	USE_INET6
170 	fprintf(stderr, "       %s -t [-46C] ", name);
171 #else
172 	fprintf(stderr, "       %s -t [-4C] ", name);
173 #endif
174 #endif
175 	fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n");
176 	exit(1);
177 }
178 
179 
180 int main(int argc, char *argv[])
181 {
182 	ipf_authstat_t	frauthst;
183 	ipf_authstat_t	*frauthstp = &frauthst;
184 	friostat_t fio;
185 	friostat_t *fiop = &fio;
186 	ips_stat_t ipsst;
187 	ips_stat_t *ipsstp = &ipsst;
188 	ipfrstat_t ifrst;
189 	ipfrstat_t *ifrstp = &ifrst;
190 	char *options;
191 	char *kern = NULL;
192 	char *memf = NULL;
193 	int c;
194 	int myoptind;
195 	int *filter = NULL;
196 
197 	int protocol = -1;		/* -1 = wild card for any protocol */
198 	int refreshtime = 1; 		/* default update time */
199 	int sport = -1;			/* -1 = wild card for any source port */
200 	int dport = -1;			/* -1 = wild card for any dest port */
201 	int topclosed = 0;		/* do not show closed tcp sessions */
202 	i6addr_t saddr, daddr;
203 	u_32_t frf;
204 
205 #ifdef	USE_INET6
206 	options = "46aACdfghIilnostvD:m:M:N:O:P:RS:T:";
207 #else
208 	options = "4aACdfghIilnostvD:m:M:N:O:P:RS:T:";
209 #endif
210 
211 	saddr.in4.s_addr = INADDR_ANY; 	/* default any v4 source addr */
212 	daddr.in4.s_addr = INADDR_ANY; 	/* default any v4 dest addr */
213 #ifdef	USE_INET6
214 	saddr.in6 = in6addr_any;	/* default any v6 source addr */
215 	daddr.in6 = in6addr_any;	/* default any v6 dest addr */
216 #endif
217 
218 	/* Don't warn about invalid flags when we run getopt for the 1st time */
219 	opterr = 0;
220 
221 	/*
222 	 * Parse these two arguments now lest there be any buffer overflows
223 	 * in the parsing of the rest.
224 	 */
225 	myoptind = optind;
226 	while ((c = getopt(argc, argv, options)) != -1) {
227 		switch (c)
228 		{
229 		case 'M' :
230 			memf = optarg;
231 			live_kernel = 0;
232 			break;
233 		case 'N' :
234 			kern = optarg;
235 			live_kernel = 0;
236 			break;
237 		}
238 	}
239 	optind = myoptind;
240 
241 	if (live_kernel == 1) {
242 		if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) {
243 			perror("open(IPSTATE_NAME)");
244 			exit(-1);
245 		}
246 		if ((auth_fd = open(IPAUTH_NAME, O_RDONLY)) == -1) {
247 			perror("open(IPAUTH_NAME)");
248 			exit(-1);
249 		}
250 		if ((nat_fd = open(IPNAT_NAME, O_RDONLY)) == -1) {
251 			perror("open(IPAUTH_NAME)");
252 			exit(-1);
253 		}
254 		if ((ipf_fd = open(IPL_NAME, O_RDONLY)) == -1) {
255 			fprintf(stderr, "open(%s)", IPL_NAME);
256 			perror("");
257 			exit(-1);
258 		}
259 	}
260 
261 	if (kern != NULL || memf != NULL) {
262 		(void)setgid(getgid());
263 		(void)setuid(getuid());
264 	}
265 
266 	if (live_kernel == 1) {
267 		(void) checkrev(IPL_NAME);
268 	} else {
269 		if (openkmem(kern, memf) == -1)
270 			exit(-1);
271 	}
272 
273 	(void)setgid(getgid());
274 	(void)setuid(getuid());
275 
276 	opterr = 1;
277 
278 	while ((c = getopt(argc, argv, options)) != -1)
279 	{
280 		switch (c)
281 		{
282 #ifdef	USE_INET6
283 		case '4' :
284 			use_inet4 = 1;
285 			break;
286 		case '6' :
287 			use_inet6 = 1;
288 			break;
289 #endif
290 		case 'a' :
291 			opts |= OPT_ACCNT|OPT_SHOWLIST;
292 			break;
293 		case 'A' :
294 			opts |= OPT_AUTHSTATS;
295 			break;
296 		case 'C' :
297 			topclosed = 1;
298 			break;
299 		case 'd' :
300 			opts |= OPT_DEBUG;
301 			break;
302 		case 'D' :
303 			parse_ipportstr(optarg, &daddr, &dport);
304 			break;
305 		case 'f' :
306 			opts |= OPT_FRSTATES;
307 			break;
308 		case 'g' :
309 			opts |= OPT_GROUPS;
310 			break;
311 		case 'h' :
312 			opts |= OPT_HITS;
313 			break;
314 		case 'i' :
315 			opts |= OPT_INQUE|OPT_SHOWLIST;
316 			break;
317 		case 'I' :
318 			opts |= OPT_INACTIVE;
319 			break;
320 		case 'l' :
321 			opts |= OPT_SHOWLIST;
322 			break;
323 		case 'm' :
324 			filter = parseipfexpr(optarg, NULL);
325 			if (filter == NULL) {
326 				fprintf(stderr, "Error parseing '%s'\n",
327 					optarg);
328 				exit(1);
329 			}
330 			break;
331 		case 'M' :
332 			break;
333 		case 'N' :
334 			break;
335 		case 'n' :
336 			opts |= OPT_SHOWLINENO;
337 			break;
338 		case 'o' :
339 			opts |= OPT_OUTQUE|OPT_SHOWLIST;
340 			break;
341 		case 'O' :
342 			state_fields = parsefields(statefields, optarg);
343 			break;
344 		case 'P' :
345 			protocol = getproto(optarg);
346 			if (protocol == -1) {
347 				fprintf(stderr, "%s: Invalid protocol: %s\n",
348 					argv[0], optarg);
349 				exit(-2);
350 			}
351 			break;
352 		case 'R' :
353 			opts |= OPT_NORESOLVE;
354 			break;
355 		case 's' :
356 			opts |= OPT_IPSTATES;
357 			break;
358 		case 'S' :
359 			parse_ipportstr(optarg, &saddr, &sport);
360 			break;
361 		case 't' :
362 #ifdef STATETOP
363 			opts |= OPT_STATETOP;
364 			break;
365 #else
366 			fprintf(stderr,
367 				"%s: state top facility not compiled in\n",
368 				argv[0]);
369 			exit(-2);
370 #endif
371 		case 'T' :
372 			if (!sscanf(optarg, "%d", &refreshtime) ||
373 				    (refreshtime <= 0)) {
374 				fprintf(stderr,
375 					"%s: Invalid refreshtime < 1 : %s\n",
376 					argv[0], optarg);
377 				exit(-2);
378 			}
379 			break;
380 		case 'v' :
381 			opts |= OPT_VERBOSE;
382 			break;
383 		default :
384 			usage(argv[0]);
385 			break;
386 		}
387 	}
388 #ifdef	USE_INET6
389 	if ((use_inet4 || use_inet6) &&
390 	   !(opts & (OPT_INQUE | OPT_OUTQUE | OPT_STATETOP))) {
391 #ifdef	STATETOP
392 		FPRINTF(stderr, "No -i, -o, or -t given with -4 or -6\n");
393 #else
394 		FPRINTF(stderr, "No -i or -o given with -4 or -6\n");
395 #endif
396 		exit(-2);
397 	}
398 	if (use_inet4 == 0 && use_inet6 == 0)
399 		use_inet4 = use_inet6 = 1;
400 #endif
401 
402 	if (live_kernel == 1) {
403 		bzero((char *)&fio, sizeof(fio));
404 		bzero((char *)&ipsst, sizeof(ipsst));
405 		bzero((char *)&ifrst, sizeof(ifrst));
406 
407 		ipfstate_live(IPL_NAME, &fiop, &ipsstp, &ifrstp,
408 			      &frauthstp, &frf);
409 	} else {
410 		ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf);
411 	}
412 
413 	if (opts & OPT_IPSTATES) {
414 		showipstates(ipsstp, filter);
415 	} else if (opts & OPT_SHOWLIST) {
416 		showlist(fiop);
417 		if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){
418 			opts &= ~OPT_OUTQUE;
419 			showlist(fiop);
420 		}
421 	} else if (opts & OPT_FRSTATES)
422 		showfrstates(ifrstp, fiop->f_ticks);
423 #ifdef STATETOP
424 	else if (opts & OPT_STATETOP)
425 		topipstates(saddr, daddr, sport, dport, protocol,
426 #ifdef	USE_INET6
427 		use_inet6 && use_inet4 ? 0 : use_inet6 && !use_inet4 ? 6 : 4,
428 #else
429 		4,
430 #endif
431 #endif
432 			    refreshtime, topclosed, filter);
433 	else if (opts & OPT_AUTHSTATS)
434 		showauthstates(frauthstp);
435 	else if (opts & OPT_GROUPS)
436 		showgroups(fiop);
437 	else
438 		showstats(fiop, frf);
439 
440 	return (0);
441 }
442 
443 
444 /*
445  * Fill in the stats structures from the live kernel, using a combination
446  * of ioctl's and copying directly from kernel memory.
447  */
448 static void ipfstate_live(char *device, friostat_t **fiopp,
449 	ips_stat_t **ipsstpp, ipfrstat_t **ifrstpp,
450 	ipf_authstat_t **frauthstpp, u_32_t *frfp)
451 {
452 	ipfobj_t ipfo;
453 
454 	if (checkrev(device) == -1) {
455 		fprintf(stderr, "User/kernel version check failed\n");
456 		exit(1);
457 	}
458 
459 	if ((opts & OPT_AUTHSTATS) == 0) {
460 		bzero((caddr_t)&ipfo, sizeof(ipfo));
461 		ipfo.ipfo_rev = IPFILTER_VERSION;
462 		ipfo.ipfo_type = IPFOBJ_IPFSTAT;
463 		ipfo.ipfo_size = sizeof(friostat_t);
464 		ipfo.ipfo_ptr = (void *)*fiopp;
465 
466 		if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) {
467 			ipferror(ipf_fd, "ioctl(ipf:SIOCGETFS)");
468 			exit(-1);
469 		}
470 
471 		if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1)
472 			ipferror(ipf_fd, "ioctl(SIOCGETFF)");
473 	}
474 
475 	if ((opts & OPT_IPSTATES) != 0) {
476 
477 		bzero((caddr_t)&ipfo, sizeof(ipfo));
478 		ipfo.ipfo_rev = IPFILTER_VERSION;
479 		ipfo.ipfo_type = IPFOBJ_STATESTAT;
480 		ipfo.ipfo_size = sizeof(ips_stat_t);
481 		ipfo.ipfo_ptr = (void *)*ipsstpp;
482 
483 		if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
484 			ipferror(state_fd, "ioctl(state:SIOCGETFS)");
485 			exit(-1);
486 		}
487 		if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) {
488 			ipferror(state_fd, "ioctl(state:SIOCGETLG)");
489 			exit(-1);
490 		}
491 	}
492 
493 	if ((opts & OPT_FRSTATES) != 0) {
494 		bzero((caddr_t)&ipfo, sizeof(ipfo));
495 		ipfo.ipfo_rev = IPFILTER_VERSION;
496 		ipfo.ipfo_type = IPFOBJ_FRAGSTAT;
497 		ipfo.ipfo_size = sizeof(ipfrstat_t);
498 		ipfo.ipfo_ptr = (void *)*ifrstpp;
499 
500 		if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) {
501 			ipferror(ipf_fd, "ioctl(SIOCGFRST)");
502 			exit(-1);
503 		}
504 	}
505 
506 	if (opts & OPT_DEBUG)
507 		PRINTF("opts %#x name %s\n", opts, device);
508 
509 	if ((opts & OPT_AUTHSTATS) != 0) {
510 		bzero((caddr_t)&ipfo, sizeof(ipfo));
511 		ipfo.ipfo_rev = IPFILTER_VERSION;
512 		ipfo.ipfo_type = IPFOBJ_AUTHSTAT;
513 		ipfo.ipfo_size = sizeof(ipf_authstat_t);
514 		ipfo.ipfo_ptr = (void *)*frauthstpp;
515 
516 	    	if (ioctl(auth_fd, SIOCATHST, &ipfo) == -1) {
517 			ipferror(auth_fd, "ioctl(SIOCATHST)");
518 			exit(-1);
519 		}
520 	}
521 }
522 
523 
524 /*
525  * Build up the stats structures from data held in the "core" memory.
526  * This is mainly useful when looking at data in crash dumps and ioctl's
527  * just won't work any more.
528  */
529 static void ipfstate_dead( char *kernel, friostat_t **fiopp,
530 	ips_stat_t **ipsstpp, ipfrstat_t **ifrstpp,
531 	ipf_authstat_t **frauthstpp, u_32_t *frfp)
532 {
533 	static ipf_authstat_t frauthst, *frauthstp;
534 	static ipftq_t ipstcptab[IPF_TCP_NSTATES];
535 	static ips_stat_t ipsst, *ipsstp;
536 	static ipfrstat_t ifrst, *ifrstp;
537 	static friostat_t fio, *fiop;
538 	int temp;
539 
540 	void *rules[2][2];
541 	struct nlist deadlist[44] = {
542 		{ "ipf_auth_stats",	0, 0, 0, 0 },		/* 0 */
543 		{ "fae_list",		0, 0, 0, 0 },
544 		{ "ipauth",		0, 0, 0, 0 },
545 		{ "ipf_auth_list",		0, 0, 0, 0 },
546 		{ "ipf_auth_start",		0, 0, 0, 0 },
547 		{ "ipf_auth_end",		0, 0, 0, 0 },		/* 5 */
548 		{ "ipf_auth_next",		0, 0, 0, 0 },
549 		{ "ipf_auth",		0, 0, 0, 0 },
550 		{ "ipf_auth_used",		0, 0, 0, 0 },
551 		{ "ipf_auth_size",		0, 0, 0, 0 },
552 		{ "ipf_auth_defaultage",		0, 0, 0, 0 },	/* 10 */
553 		{ "ipf_auth_pkts",		0, 0, 0, 0 },
554 		{ "ipf_auth_lock",		0, 0, 0, 0 },
555 		{ "frstats",		0, 0, 0, 0 },
556 		{ "ips_stats",		0, 0, 0, 0 },
557 		{ "ips_num",		0, 0, 0, 0 },			/* 15 */
558 		{ "ips_wild",		0, 0, 0, 0 },
559 		{ "ips_list",		0, 0, 0, 0 },
560 		{ "ips_table",		0, 0, 0, 0 },
561 		{ "ipf_state_max",		0, 0, 0, 0 },
562 		{ "ipf_state_size",		0, 0, 0, 0 },		/* 20 */
563 		{ "ipf_state_doflush",		0, 0, 0, 0 },
564 		{ "ipf_state_lock",		0, 0, 0, 0 },
565 		{ "ipfr_heads",		0, 0, 0, 0 },
566 		{ "ipfr_nattab",		0, 0, 0, 0 },
567 		{ "ipfr_stats",		0, 0, 0, 0 },		/* 25 */
568 		{ "ipfr_inuse",		0, 0, 0, 0 },
569 		{ "ipf_ipfrttl",		0, 0, 0, 0 },
570 		{ "ipf_frag_lock",		0, 0, 0, 0 },
571 		{ "ipfr_timer_id",		0, 0, 0, 0 },
572 		{ "ipf_nat_lock",		0, 0, 0, 0 },		/* 30 */
573 		{ "ipf_rules",		0, 0, 0, 0 },
574 		{ "ipf_acct",		0, 0, 0, 0 },
575 		{ "ipl_frouteok",		0, 0, 0, 0 },
576 		{ "ipf_running",		0, 0, 0, 0 },
577 		{ "ipf_groups",		0, 0, 0, 0 },		/* 35 */
578 		{ "ipf_active",		0, 0, 0, 0 },
579 		{ "ipf_pass",		0, 0, 0, 0 },
580 		{ "ipf_flags",		0, 0, 0, 0 },
581 		{ "ipf_state_logging",		0, 0, 0, 0 },
582 		{ "ips_tqtqb",		0, 0, 0, 0 },		/* 40 */
583 		{ NULL,		0, 0, 0, 0 }
584 	};
585 
586 
587 	frauthstp = &frauthst;
588 	ipsstp = &ipsst;
589 	ifrstp = &ifrst;
590 	fiop = &fio;
591 
592 	*frfp = 0;
593 	*fiopp = fiop;
594 	*ipsstpp = ipsstp;
595 	*ifrstpp = ifrstp;
596 	*frauthstpp = frauthstp;
597 
598 	bzero((char *)fiop, sizeof(*fiop));
599 	bzero((char *)ipsstp, sizeof(*ipsstp));
600 	bzero((char *)ifrstp, sizeof(*ifrstp));
601 	bzero((char *)frauthstp, sizeof(*frauthstp));
602 
603 	if (nlist(kernel, deadlist) == -1) {
604 		fprintf(stderr, "nlist error\n");
605 		return;
606 	}
607 
608 	/*
609 	 * This is for SIOCGETFF.
610 	 */
611 	kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp));
612 
613 	/*
614 	 * f_locks is a combination of the lock variable from each part of
615 	 * ipfilter (state, auth, nat, fragments).
616 	 */
617 	kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop));
618 	kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value,
619 		sizeof(fiop->f_locks[0]));
620 	kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value,
621 		sizeof(fiop->f_locks[1]));
622 	kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value,
623 		sizeof(fiop->f_locks[2]));
624 	kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value,
625 		sizeof(fiop->f_locks[3]));
626 
627 	/*
628 	 * Get pointers to each list of rules (active, inactive, in, out)
629 	 */
630 	kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules));
631 	fiop->f_fin[0] = rules[0][0];
632 	fiop->f_fin[1] = rules[0][1];
633 	fiop->f_fout[0] = rules[1][0];
634 	fiop->f_fout[1] = rules[1][1];
635 
636 	/*
637 	 * Now get accounting rules pointers.
638 	 */
639 	kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules));
640 	fiop->f_acctin[0] = rules[0][0];
641 	fiop->f_acctin[1] = rules[0][1];
642 	fiop->f_acctout[0] = rules[1][0];
643 	fiop->f_acctout[1] = rules[1][1];
644 
645 	/*
646 	 * A collection of "global" variables used inside the kernel which
647 	 * are all collected in friostat_t via ioctl.
648 	 */
649 	kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[33].n_value,
650 		sizeof(fiop->f_froute));
651 	kmemcpy((char *)&fiop->f_running, (u_long)deadlist[34].n_value,
652 		sizeof(fiop->f_running));
653 	kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[35].n_value,
654 		sizeof(fiop->f_groups));
655 	kmemcpy((char *)&fiop->f_active, (u_long)deadlist[36].n_value,
656 		sizeof(fiop->f_active));
657 	kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[37].n_value,
658 		sizeof(fiop->f_defpass));
659 
660 	/*
661 	 * Build up the state information stats structure.
662 	 */
663 	kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp));
664 	kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp));
665 	kmemcpy((char *)ipstcptab, (u_long)deadlist[40].n_value,
666 		sizeof(ipstcptab));
667 	ipsstp->iss_active = temp;
668 	ipsstp->iss_table = (void *)deadlist[18].n_value;
669 	ipsstp->iss_list = (void *)deadlist[17].n_value;
670 	ipsstp->iss_tcptab = ipstcptab;
671 
672 	/*
673 	 * Build up the authentiation information stats structure.
674 	 */
675 	kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value,
676 		sizeof(*frauthstp));
677 	frauthstp->fas_faelist = (void *)deadlist[1].n_value;
678 
679 	/*
680 	 * Build up the fragment information stats structure.
681 	 */
682 	kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value,
683 		sizeof(*ifrstp));
684 	ifrstp->ifs_table = (void *)deadlist[23].n_value;
685 	ifrstp->ifs_nattab = (void *)deadlist[24].n_value;
686 	kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value,
687 		sizeof(ifrstp->ifs_inuse));
688 
689 	/*
690 	 * Get logging on/off switches
691 	 */
692 	kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value,
693 		sizeof(state_logging));
694 }
695 
696 
697 static void printside(char *side, ipf_statistics_t *frs)
698 {
699 	int i;
700 
701 	PRINTF("%lu\t%s bad packets\n", frs->fr_bad, side);
702 #ifdef	USE_INET6
703 	PRINTF("%lu\t%s IPv6 packets\n", frs->fr_ipv6, side);
704 #endif
705 	PRINTF("%lu\t%s packets blocked\n", frs->fr_block, side);
706 	PRINTF("%lu\t%s packets passed\n", frs->fr_pass, side);
707 	PRINTF("%lu\t%s packets not matched\n", frs->fr_nom, side);
708 	PRINTF("%lu\t%s packets counted\n", frs->fr_acct, side);
709 	PRINTF("%lu\t%s packets short\n", frs->fr_short, side);
710 	PRINTF("%lu\t%s packets logged and blocked\n", frs->fr_bpkl, side);
711 	PRINTF("%lu\t%s packets logged and passed\n", frs->fr_ppkl, side);
712 	PRINTF("%lu\t%s fragment state kept\n", frs->fr_nfr, side);
713 	PRINTF("%lu\t%s fragment state lost\n", frs->fr_bnfr, side);
714 	PRINTF("%lu\t%s packet state kept\n", frs->fr_ads, side);
715 	PRINTF("%lu\t%s packet state lost\n", frs->fr_bads, side);
716 	PRINTF("%lu\t%s invalid source\n", frs->fr_v4_badsrc, side);
717 	PRINTF("%lu\t%s cache hits\n", frs->fr_chit, side);
718 	PRINTF("%lu\t%s cache misses\n", frs->fr_cmiss, side);
719 	PRINTF("%lu\t%s bad coalesces\n", frs->fr_badcoalesces, side);
720 	PRINTF("%lu\t%s pullups succeeded\n", frs->fr_pull[0], side);
721 	PRINTF("%lu\t%s pullups failed\n", frs->fr_pull[1], side);
722 	PRINTF("%lu\t%s TCP checksum failures\n", frs->fr_tcpbad, side);
723 	for (i = 0; i <= FRB_MAX_VALUE; i++)
724 		PRINTF("%lu\t%s block reason %s\n",
725 			frs->fr_blocked[i], side, blockreasons[i]);
726 }
727 
728 
729 /*
730  * Display the kernel stats for packets blocked and passed and other
731  * associated running totals which are kept.
732  */
733 static	void	showstats( struct friostat *fp, u_32_t frf)
734 {
735 	printside("input", &fp->f_st[0]);
736 	printside("output", &fp->f_st[1]);
737 
738 	PRINTF("%lu\tpackets logged\n", fp->f_log_ok);
739 	PRINTF("%lu\tlog failures\n", fp->f_log_fail);
740 	PRINTF("%lu\tred-black no memory\n", fp->f_rb_no_mem);
741 	PRINTF("%lu\tred-black node maximum\n", fp->f_rb_node_max);
742 	PRINTF("%lu\tICMP replies sent\n", fp->f_st[0].fr_ret);
743 	PRINTF("%lu\tTCP RSTs sent\n", fp->f_st[1].fr_ret);
744 	PRINTF("%lu\tfastroute successes\n", fp->f_froute[0]);
745 	PRINTF("%lu\tfastroute failures\n", fp->f_froute[1]);
746 	PRINTF("%u\tIPF Ticks\n", fp->f_ticks);
747 
748 	PRINTF("%x\tPacket log flags set:\n", frf);
749 	if (frf & FF_LOGPASS)
750 		PRINTF("\tpackets passed through filter\n");
751 	if (frf & FF_LOGBLOCK)
752 		PRINTF("\tpackets blocked by filter\n");
753 	if (frf & FF_LOGNOMATCH)
754 		PRINTF("\tpackets not matched by filter\n");
755 	if (!frf)
756 		PRINTF("\tnone\n");
757 }
758 
759 
760 /*
761  * Print out a list of rules from the kernel, starting at the one passed.
762  */
763 static int
764 printlivelist( struct friostat *fiop, int out, int set, frentry_t *fp,
765 	char *group, char *comment)
766 {
767 	struct	frentry	fb;
768 	ipfruleiter_t rule;
769 	frentry_t zero;
770 	frgroup_t *g;
771 	ipfobj_t obj;
772 	int rules;
773 	int num;
774 
775 	rules = 0;
776 
777 	rule.iri_inout = out;
778 	rule.iri_active = set;
779 	rule.iri_rule = &fb;
780 	rule.iri_nrules = 1;
781 	if (group != NULL)
782 		strncpy(rule.iri_group, group, FR_GROUPLEN);
783 	else
784 		rule.iri_group[0] = '\0';
785 
786 	bzero((char *)&zero, sizeof(zero));
787 
788 	bzero((char *)&obj, sizeof(obj));
789 	obj.ipfo_rev = IPFILTER_VERSION;
790 	obj.ipfo_type = IPFOBJ_IPFITER;
791 	obj.ipfo_size = sizeof(rule);
792 	obj.ipfo_ptr = &rule;
793 
794 	while (rule.iri_rule != NULL) {
795 		u_long array[1000];
796 
797 		memset(array, 0xff, sizeof(array));
798 		fp = (frentry_t *)array;
799 		rule.iri_rule = fp;
800 		if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) {
801 			ipferror(ipf_fd, "ioctl(SIOCIPFITER)");
802 			num = IPFGENITER_IPF;
803 			(void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
804 			return (rules);
805 		}
806 		if (bcmp(fp, &zero, sizeof(zero)) == 0)
807 			break;
808 		if (rule.iri_rule == NULL)
809 			break;
810 #ifdef USE_INET6
811 		if (use_inet6 != 0 && use_inet4 == 0) {
812 			if (fp->fr_family != 0 && fp->fr_family != AF_INET6)
813 				continue;
814 		} else if (use_inet4 != 0 && use_inet6 == 0) {
815 #endif
816 			if (fp->fr_family != 0 && fp->fr_family != AF_INET)
817 				continue;
818 #ifdef USE_INET6
819 		} else {
820 			if (fp->fr_family != 0 &&
821 			   fp->fr_family != AF_INET && fp->fr_family != AF_INET6)
822 				continue;
823 		}
824 #endif
825 
826 		if (fp->fr_data != NULL)
827 			fp->fr_data = (char *)fp + fp->fr_size;
828 
829 		rules++;
830 
831 		if (opts & (OPT_HITS|OPT_DEBUG))
832 #ifdef	USE_QUAD_T
833 			PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_hits);
834 #else
835 			PRINTF("%lu ", fp->fr_hits);
836 #endif
837 		if (opts & (OPT_ACCNT|OPT_DEBUG))
838 #ifdef	USE_QUAD_T
839 			PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_bytes);
840 #else
841 			PRINTF("%lu ", fp->fr_bytes);
842 #endif
843 		if (opts & OPT_SHOWLINENO)
844 			PRINTF("@%d ", rules);
845 
846 		if (fp->fr_die != 0)
847 			fp->fr_die -= fiop->f_ticks;
848 
849 		printfr(fp, ioctl);
850 		if (opts & OPT_DEBUG) {
851 			binprint(fp, fp->fr_size);
852 			if (fp->fr_data != NULL && fp->fr_dsize > 0)
853 				binprint(fp->fr_data, fp->fr_dsize);
854 		}
855 		if (fp->fr_grhead != -1) {
856 			for (g = grtop; g != NULL; g = g->fg_next) {
857 				if (!strncmp(fp->fr_names + fp->fr_grhead,
858 					     g->fg_name,
859 					     FR_GROUPLEN))
860 					break;
861 			}
862 			if (g == NULL) {
863 				g = calloc(1, sizeof(*g));
864 
865 				if (g != NULL) {
866 					strncpy(g->fg_name,
867 						fp->fr_names + fp->fr_grhead,
868 						FR_GROUPLEN);
869 					if (grtop == NULL) {
870 						grtop = g;
871 						grtail = g;
872 					} else {
873 						grtail->fg_next = g;
874 						grtail = g;
875 					}
876 				}
877 			}
878 		}
879 		if (fp->fr_type == FR_T_CALLFUNC) {
880 			rules += printlivelist(fiop, out, set, fp->fr_data,
881 					       group, "# callfunc: ");
882 		}
883 	}
884 
885 	num = IPFGENITER_IPF;
886 	(void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
887 
888 	return (rules);
889 }
890 
891 
892 static void printdeadlist(friostat_t *fiop, int out, int set, frentry_t *fp,
893 	char *group, char *comment)
894 {
895 	frgroup_t *grtop, *grtail, *g;
896 	struct	frentry	fb;
897 	char	*data;
898 	u_32_t	type;
899 	int	n;
900 
901 	fb.fr_next = fp;
902 	n = 0;
903 	grtop = NULL;
904 	grtail = NULL;
905 
906 	for (n = 1; fp; fp = fb.fr_next, n++) {
907 		if (kmemcpy((char *)&fb, (u_long)fb.fr_next,
908 			    fb.fr_size) == -1) {
909 			perror("kmemcpy");
910 			return;
911 		}
912 		fp = &fb;
913 #ifdef	USE_INET6
914 		if (use_inet6 != 0 && use_inet4 == 0) {
915 			if (fp->fr_family != 0 && fp->fr_family != AF_INET6)
916 				continue;
917 		} else if (use_inet4 != 0 && use_inet6 == 0) {
918 #endif
919 			if (fp->fr_family != 0 && fp->fr_family != AF_INET)
920 				continue;
921 #ifdef	USE_INET6
922 		} else {
923 			if (fp->fr_family != 0 &&
924 			   fp->fr_family != AF_INET && fp->fr_family != AF_INET6)
925 				continue;
926 		}
927 #endif
928 
929 		data = NULL;
930 		type = fb.fr_type & ~FR_T_BUILTIN;
931 		if (type == FR_T_IPF || type == FR_T_BPFOPC) {
932 			if (fb.fr_dsize) {
933 				data = malloc(fb.fr_dsize);
934 
935 				if (kmemcpy(data, (u_long)fb.fr_data,
936 					    fb.fr_dsize) == -1) {
937 					perror("kmemcpy");
938 					return;
939 				}
940 				fb.fr_data = data;
941 			}
942 		}
943 
944 		if (opts & OPT_HITS)
945 #ifdef	USE_QUAD_T
946 			PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_hits);
947 #else
948 			PRINTF("%lu ", fb.fr_hits);
949 #endif
950 		if (opts & OPT_ACCNT)
951 #ifdef	USE_QUAD_T
952 			PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_bytes);
953 #else
954 			PRINTF("%lu ", fb.fr_bytes);
955 #endif
956 		if (opts & OPT_SHOWLINENO)
957 			PRINTF("@%d ", n);
958 
959 		printfr(fp, ioctl);
960 		if (opts & OPT_DEBUG) {
961 			binprint(fp, fp->fr_size);
962 			if (fb.fr_data != NULL && fb.fr_dsize > 0)
963 				binprint(fb.fr_data, fb.fr_dsize);
964 		}
965 		if (data != NULL)
966 			free(data);
967 		if (fb.fr_grhead != -1) {
968 			g = calloc(1, sizeof(*g));
969 
970 			if (g != NULL) {
971 				strncpy(g->fg_name, fb.fr_names + fb.fr_grhead,
972 					FR_GROUPLEN);
973 				if (grtop == NULL) {
974 					grtop = g;
975 					grtail = g;
976 				} else {
977 					grtail->fg_next = g;
978 					grtail = g;
979 				}
980 			}
981 		}
982 		if (type == FR_T_CALLFUNC) {
983 			printdeadlist(fiop, out, set, fb.fr_data, group,
984 				      "# callfunc: ");
985 		}
986 	}
987 
988 	while ((g = grtop) != NULL) {
989 		printdeadlist(fiop, out, set, NULL, g->fg_name, comment);
990 		grtop = g->fg_next;
991 		free(g);
992 	}
993 }
994 
995 /*
996  * print out all of the asked for rule sets, using the stats struct as
997  * the base from which to get the pointers.
998  */
999 static	void	showlist(struct friostat *fiop)
1000 {
1001 	struct	frentry	*fp = NULL;
1002 	int	i, set;
1003 
1004 	set = fiop->f_active;
1005 	if (opts & OPT_INACTIVE)
1006 		set = 1 - set;
1007 	if (opts & OPT_ACCNT) {
1008 		if (opts & OPT_OUTQUE) {
1009 			i = F_ACOUT;
1010 			fp = (struct frentry *)fiop->f_acctout[set];
1011 		} else if (opts & OPT_INQUE) {
1012 			i = F_ACIN;
1013 			fp = (struct frentry *)fiop->f_acctin[set];
1014 		} else {
1015 			FPRINTF(stderr, "No -i or -o given with -a\n");
1016 			return;
1017 		}
1018 	} else {
1019 		if (opts & OPT_OUTQUE) {
1020 			i = F_OUT;
1021 			fp = (struct frentry *)fiop->f_fout[set];
1022 		} else if (opts & OPT_INQUE) {
1023 			i = F_IN;
1024 			fp = (struct frentry *)fiop->f_fin[set];
1025 		} else
1026 			return;
1027 	}
1028 	if (opts & OPT_DEBUG)
1029 		FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
1030 
1031 	if (opts & OPT_DEBUG)
1032 		PRINTF("fp %p set %d\n", fp, set);
1033 
1034 	if (live_kernel == 1) {
1035 		int printed;
1036 
1037 		printed = printlivelist(fiop, i, set, fp, NULL, NULL);
1038 		if (printed == 0) {
1039 			FPRINTF(stderr, "# empty list for %s%s\n",
1040 			        (opts & OPT_INACTIVE) ? "inactive " : "",
1041 							filters[i]);
1042 		}
1043 	} else {
1044 		if (!fp) {
1045 			FPRINTF(stderr, "# empty list for %s%s\n",
1046 			        (opts & OPT_INACTIVE) ? "inactive " : "",
1047 							filters[i]);
1048 		} else {
1049 			printdeadlist(fiop, i, set, fp, NULL, NULL);
1050 		}
1051 	}
1052 }
1053 
1054 
1055 /*
1056  * Display ipfilter stateful filtering information
1057  */
1058 static void showipstates(ips_stat_t *ipsp, int *filter)
1059 {
1060 	ipstate_t *is;
1061 	int i;
1062 
1063 	/*
1064 	 * If a list of states hasn't been asked for, only print out stats
1065 	 */
1066 	if (!(opts & OPT_SHOWLIST)) {
1067 		showstatestats(ipsp);
1068 		return;
1069 	}
1070 
1071 	if ((state_fields != NULL) && (nohdrfields == 0)) {
1072 		for (i = 0; state_fields[i].w_value != 0; i++) {
1073 			printfieldhdr(statefields, state_fields + i);
1074 			if (state_fields[i + 1].w_value != 0)
1075 				printf("\t");
1076 		}
1077 		printf("\n");
1078 	}
1079 
1080 	/*
1081 	 * Print out all the state information currently held in the kernel.
1082 	 */
1083 	for (is = ipsp->iss_list; is != NULL; ) {
1084 		ipstate_t ips;
1085 
1086 		is = fetchstate(is, &ips);
1087 
1088 		if (is == NULL)
1089 			break;
1090 
1091 		is = ips.is_next;
1092 		if ((filter != NULL) &&
1093 		    (state_matcharray(&ips, filter) == 0)) {
1094 			continue;
1095 		}
1096 		if (state_fields != NULL) {
1097 			for (i = 0; state_fields[i].w_value != 0; i++) {
1098 				printstatefield(&ips, state_fields[i].w_value);
1099 				if (state_fields[i + 1].w_value != 0)
1100 					printf("\t");
1101 			}
1102 			printf("\n");
1103 		} else {
1104 			printstate(&ips, opts, ipsp->iss_ticks);
1105 		}
1106 	}
1107 }
1108 
1109 
1110 static void showstatestats(ips_stat_t *ipsp)
1111 {
1112 	int minlen, maxlen, totallen;
1113 	ipftable_t table;
1114 	u_int *buckets;
1115 	ipfobj_t obj;
1116 	int i, sz;
1117 
1118 	/*
1119 	 * If a list of states hasn't been asked for, only print out stats
1120 	 */
1121 
1122 	sz = sizeof(*buckets) * ipsp->iss_state_size;
1123 	buckets = (u_int *)malloc(sz);
1124 
1125 	obj.ipfo_rev = IPFILTER_VERSION;
1126 	obj.ipfo_type = IPFOBJ_GTABLE;
1127 	obj.ipfo_size = sizeof(table);
1128 	obj.ipfo_ptr = &table;
1129 
1130 	table.ita_type = IPFTABLE_BUCKETS;
1131 	table.ita_table = buckets;
1132 
1133 	if (live_kernel == 1) {
1134 		if (ioctl(state_fd, SIOCGTABL, &obj) != 0) {
1135 			free(buckets);
1136 			return;
1137 		}
1138 	} else {
1139 		if (kmemcpy((char *)buckets,
1140 			    (u_long)ipsp->iss_bucketlen, sz)) {
1141 			free(buckets);
1142 			return;
1143 		}
1144 	}
1145 
1146 	PRINTF("%u\tactive state table entries\n",ipsp->iss_active);
1147 	PRINTF("%lu\tadd bad\n", ipsp->iss_add_bad);
1148 	PRINTF("%lu\tadd duplicate\n", ipsp->iss_add_dup);
1149 	PRINTF("%lu\tadd locked\n", ipsp->iss_add_locked);
1150 	PRINTF("%lu\tadd oow\n", ipsp->iss_add_oow);
1151 	PRINTF("%lu\tbucket full\n", ipsp->iss_bucket_full);
1152 	PRINTF("%lu\tcheck bad\n", ipsp->iss_check_bad);
1153 	PRINTF("%lu\tcheck miss\n", ipsp->iss_check_miss);
1154 	PRINTF("%lu\tcheck nattag\n", ipsp->iss_check_nattag);
1155 	PRINTF("%lu\tclone nomem\n", ipsp->iss_clone_nomem);
1156 	PRINTF("%lu\tcheck notag\n", ipsp->iss_check_notag);
1157 	PRINTF("%lu\tcheck success\n", ipsp->iss_hits);
1158 	PRINTF("%lu\tcloned\n", ipsp->iss_cloned);
1159 	PRINTF("%lu\texpired\n", ipsp->iss_expire);
1160 	PRINTF("%lu\tflush all\n", ipsp->iss_flush_all);
1161 	PRINTF("%lu\tflush closing\n", ipsp->iss_flush_closing);
1162 	PRINTF("%lu\tflush queue\n", ipsp->iss_flush_queue);
1163 	PRINTF("%lu\tflush state\n", ipsp->iss_flush_state);
1164 	PRINTF("%lu\tflush timeout\n", ipsp->iss_flush_timeout);
1165 	PRINTF("%u\thash buckets in use\n", ipsp->iss_inuse);
1166 	PRINTF("%lu\tICMP bad\n", ipsp->iss_icmp_bad);
1167 	PRINTF("%lu\tICMP banned\n", ipsp->iss_icmp_banned);
1168 	PRINTF("%lu\tICMP errors\n", ipsp->iss_icmp_icmperr);
1169 	PRINTF("%lu\tICMP head block\n", ipsp->iss_icmp_headblock);
1170 	PRINTF("%lu\tICMP hits\n", ipsp->iss_icmp_hits);
1171 	PRINTF("%lu\tICMP not query\n",	ipsp->iss_icmp_notquery);
1172 	PRINTF("%lu\tICMP short\n", ipsp->iss_icmp_short);
1173 	PRINTF("%lu\tICMP too many\n", ipsp->iss_icmp_toomany);
1174 	PRINTF("%lu\tICMPv6 errors\n", ipsp->iss_icmp6_icmperr);
1175 	PRINTF("%lu\tICMPv6 miss\n", ipsp->iss_icmp6_miss);
1176 	PRINTF("%lu\tICMPv6 not info\n", ipsp->iss_icmp6_notinfo);
1177 	PRINTF("%lu\tICMPv6 not query\n", ipsp->iss_icmp6_notquery);
1178 	PRINTF("%lu\tlog fail\n", ipsp->iss_log_fail);
1179 	PRINTF("%lu\tlog ok\n", ipsp->iss_log_ok);
1180 	PRINTF("%lu\tlookup interface mismatch\n", ipsp->iss_lookup_badifp);
1181 	PRINTF("%lu\tlookup mask mismatch\n", ipsp->iss_miss_mask);
1182 	PRINTF("%lu\tlookup port mismatch\n", ipsp->iss_lookup_badport);
1183 	PRINTF("%lu\tlookup miss\n", ipsp->iss_lookup_miss);
1184 	PRINTF("%lu\tmaximum rule references\n", ipsp->iss_max_ref);
1185 	PRINTF("%lu\tmaximum hosts per rule\n", ipsp->iss_max_track);
1186 	PRINTF("%lu\tno memory\n", ipsp->iss_nomem);
1187 	PRINTF("%lu\tout of window\n", ipsp->iss_oow);
1188 	PRINTF("%lu\torphans\n", ipsp->iss_orphan);
1189 	PRINTF("%lu\tscan block\n", ipsp->iss_scan_block);
1190 	PRINTF("%lu\tstate table maximum reached\n", ipsp->iss_max);
1191 	PRINTF("%lu\tTCP closing\n", ipsp->iss_tcp_closing);
1192 	PRINTF("%lu\tTCP OOW\n", ipsp->iss_tcp_oow);
1193 	PRINTF("%lu\tTCP RST add\n", ipsp->iss_tcp_rstadd);
1194 	PRINTF("%lu\tTCP too small\n", ipsp->iss_tcp_toosmall);
1195 	PRINTF("%lu\tTCP bad options\n", ipsp->iss_tcp_badopt);
1196 	PRINTF("%lu\tTCP removed\n", ipsp->iss_fin);
1197 	PRINTF("%lu\tTCP FSM\n", ipsp->iss_tcp_fsm);
1198 	PRINTF("%lu\tTCP strict\n", ipsp->iss_tcp_strict);
1199 	PRINTF("%lu\tTCP wild\n", ipsp->iss_wild);
1200 	PRINTF("%lu\tMicrosoft Windows SACK\n", ipsp->iss_winsack);
1201 
1202 	PRINTF("State logging %sabled\n", state_logging ? "en" : "dis");
1203 
1204 	PRINTF("IP states added:\n");
1205 	for (i = 0; i < 256; i++) {
1206 		if (ipsp->iss_proto[i] != 0) {
1207 			struct protoent *proto;
1208 
1209 			proto = getprotobynumber(i);
1210 			PRINTF("%lu", ipsp->iss_proto[i]);
1211 			if (proto != NULL)
1212 				PRINTF("\t%s\n", proto->p_name);
1213 			else
1214 				PRINTF("\t%d\n", i);
1215 		}
1216 	}
1217 
1218 	PRINTF("\nState table bucket statistics:\n");
1219 	PRINTF("%u\tin use\n", ipsp->iss_inuse);
1220 
1221 	minlen = ipsp->iss_max;
1222 	totallen = 0;
1223 	maxlen = 0;
1224 
1225 	for (i = 0; i < ipsp->iss_state_size; i++) {
1226 		if (buckets[i] > maxlen)
1227 			maxlen = buckets[i];
1228 		if (buckets[i] < minlen)
1229 			minlen = buckets[i];
1230 		totallen += buckets[i];
1231 	}
1232 
1233 	PRINTF("%d\thash efficiency\n",
1234 		totallen ? ipsp->iss_inuse * 100 / totallen : 0);
1235 	PRINTF("%2.2f%%\tbucket usage\n%u\tminimal length\n",
1236 		((float)ipsp->iss_inuse / ipsp->iss_state_size) * 100.0,
1237 		minlen);
1238 	PRINTF("%u\tmaximal length\n%.3f\taverage length\n",
1239 		maxlen,
1240 		ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse :
1241 				  0.0);
1242 
1243 #define ENTRIES_PER_LINE 5
1244 
1245 	if (opts & OPT_VERBOSE) {
1246 		PRINTF("\nCurrent bucket sizes :\n");
1247 		for (i = 0; i < ipsp->iss_state_size; i++) {
1248 			if ((i % ENTRIES_PER_LINE) == 0)
1249 				PRINTF("\t");
1250 			PRINTF("%4d -> %4u", i, buckets[i]);
1251 			if ((i % ENTRIES_PER_LINE) ==
1252 			    (ENTRIES_PER_LINE - 1))
1253 				PRINTF("\n");
1254 			else
1255 				PRINTF("  ");
1256 		}
1257 		PRINTF("\n");
1258 	}
1259 	PRINTF("\n");
1260 
1261 	free(buckets);
1262 
1263 	if (live_kernel == 1) {
1264 		showtqtable_live(state_fd);
1265 	} else {
1266 		printtqtable(ipsp->iss_tcptab);
1267 	}
1268 }
1269 
1270 
1271 #ifdef STATETOP
1272 static int handle_resize = 0, handle_break = 0;
1273 
1274 static void topipstates(i6addr_t saddr, i6addr_t daddr, int sport, int dport,
1275 	int protocol, int ver, int refreshtime, int topclosed, int *filter)
1276 {
1277 	char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
1278 	int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
1279 	int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0;
1280 	int len, srclen, dstlen, forward = 1, c = 0;
1281 	ips_stat_t ipsst, *ipsstp = &ipsst;
1282 	int token_type = IPFGENITER_STATE;
1283 	statetop_t *tstable = NULL, *tp;
1284 	const char *errstr = "";
1285 	ipstate_t ips;
1286 	ipfobj_t ipfo;
1287 	struct timeval selecttimeout;
1288 	char hostnm[HOSTNMLEN];
1289 	struct protoent *proto;
1290 	fd_set readfd;
1291 	time_t t;
1292 
1293 	/* install signal handlers */
1294 	signal(SIGINT, sig_break);
1295 	signal(SIGQUIT, sig_break);
1296 	signal(SIGTERM, sig_break);
1297 	signal(SIGWINCH, sig_resize);
1298 
1299 	/* init ncurses stuff */
1300   	initscr();
1301   	cbreak();
1302   	noecho();
1303 	curs_set(0);
1304 	timeout(0);
1305 	getmaxyx(stdscr, maxy, maxx);
1306 
1307 	/* init hostname */
1308 	gethostname(hostnm, sizeof(hostnm) - 1);
1309 	hostnm[sizeof(hostnm) - 1] = '\0';
1310 
1311 	/* init ipfobj_t stuff */
1312 	bzero((caddr_t)&ipfo, sizeof(ipfo));
1313 	ipfo.ipfo_rev = IPFILTER_VERSION;
1314 	ipfo.ipfo_type = IPFOBJ_STATESTAT;
1315 	ipfo.ipfo_size = sizeof(*ipsstp);
1316 	ipfo.ipfo_ptr = (void *)ipsstp;
1317 
1318 	/* repeat until user aborts */
1319 	while ( 1 ) {
1320 
1321 		/* get state table */
1322 		bzero((char *)&ipsst, sizeof(ipsst));
1323 		if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
1324 			errstr = "ioctl(SIOCGETFS)";
1325 			ret = -1;
1326 			goto out;
1327 		}
1328 
1329 		/* clear the history */
1330 		tsentry = -1;
1331 
1332 		/* reset max str len */
1333 		srclen = dstlen = 0;
1334 
1335 		/* read the state table and store in tstable */
1336 		for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
1337 
1338 			ipsstp->iss_list = fetchstate(ipsstp->iss_list, &ips);
1339 			if (ipsstp->iss_list == NULL)
1340 				break;
1341 
1342 			if (ver != 0 && ips.is_v != ver)
1343 				continue;
1344 
1345 			if ((filter != NULL) &&
1346 			    (state_matcharray(&ips, filter) == 0))
1347 				continue;
1348 
1349 			/* check v4 src/dest addresses */
1350 			if (ips.is_v == 4) {
1351 				if ((saddr.in4.s_addr != INADDR_ANY &&
1352 				     saddr.in4.s_addr != ips.is_saddr) ||
1353 				    (daddr.in4.s_addr != INADDR_ANY &&
1354 				     daddr.in4.s_addr != ips.is_daddr))
1355 					continue;
1356 			}
1357 #ifdef	USE_INET6
1358 			/* check v6 src/dest addresses */
1359 			if (ips.is_v == 6) {
1360 				if ((IP6_NEQ(&saddr, &in6addr_any) &&
1361 				     IP6_NEQ(&saddr, &ips.is_src)) ||
1362 				    (IP6_NEQ(&daddr, &in6addr_any) &&
1363 				     IP6_NEQ(&daddr, &ips.is_dst)))
1364 					continue;
1365 			}
1366 #endif
1367 			/* check protocol */
1368 			if (protocol > 0 && protocol != ips.is_p)
1369 				continue;
1370 
1371 			/* check ports if protocol is TCP or UDP */
1372 			if (((ips.is_p == IPPROTO_TCP) ||
1373 			     (ips.is_p == IPPROTO_UDP)) &&
1374 			   (((sport > 0) && (htons(sport) != ips.is_sport)) ||
1375 			    ((dport > 0) && (htons(dport) != ips.is_dport))))
1376 				continue;
1377 
1378 			/* show closed TCP sessions ? */
1379 			if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
1380 			    (ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
1381 			    (ips.is_state[1] >= IPF_TCPS_LAST_ACK))
1382 				continue;
1383 
1384 			/*
1385 			 * if necessary make room for this state
1386 			 * entry
1387 			 */
1388 			tsentry++;
1389 			if (!maxtsentries || tsentry == maxtsentries) {
1390 				maxtsentries += STGROWSIZE;
1391 				tstable = reallocarray(tstable, maxtsentries,
1392 				    sizeof(statetop_t));
1393 				if (tstable == NULL) {
1394 					perror("realloc");
1395 					exit(-1);
1396 				}
1397 			}
1398 
1399 			/* get max src/dest address string length */
1400 			len = strlen(getip(ips.is_v, &ips.is_src));
1401 			if (srclen < len)
1402 				srclen = len;
1403 			len = strlen(getip(ips.is_v, &ips.is_dst));
1404 			if (dstlen < len)
1405 				dstlen = len;
1406 
1407 			/* fill structure */
1408 			tp = tstable + tsentry;
1409 			tp->st_src = ips.is_src;
1410 			tp->st_dst = ips.is_dst;
1411 			tp->st_p = ips.is_p;
1412 			tp->st_v = ips.is_v;
1413 			tp->st_state[0] = ips.is_state[0];
1414 			tp->st_state[1] = ips.is_state[1];
1415 			if (forward) {
1416 				tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
1417 				tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
1418 			} else {
1419 				tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3];
1420 				tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3];
1421 			}
1422 			tp->st_age = ips.is_die - ipsstp->iss_ticks;
1423 			if ((ips.is_p == IPPROTO_TCP) ||
1424 			    (ips.is_p == IPPROTO_UDP)) {
1425 				tp->st_sport = ips.is_sport;
1426 				tp->st_dport = ips.is_dport;
1427 			}
1428 		}
1429 
1430 		(void) ioctl(state_fd, SIOCIPFDELTOK, &token_type);
1431 
1432 		/* sort the array */
1433 		if (tsentry != -1) {
1434 			switch (sorting)
1435 			{
1436 			case STSORT_PR:
1437 				qsort(tstable, tsentry + 1,
1438 				      sizeof(statetop_t), sort_p);
1439 				break;
1440 			case STSORT_PKTS:
1441 				qsort(tstable, tsentry + 1,
1442 				      sizeof(statetop_t), sort_pkts);
1443 				break;
1444 			case STSORT_BYTES:
1445 				qsort(tstable, tsentry + 1,
1446 				      sizeof(statetop_t), sort_bytes);
1447 				break;
1448 			case STSORT_TTL:
1449 				qsort(tstable, tsentry + 1,
1450 				      sizeof(statetop_t), sort_ttl);
1451 				break;
1452 			case STSORT_SRCIP:
1453 				qsort(tstable, tsentry + 1,
1454 				      sizeof(statetop_t), sort_srcip);
1455 				break;
1456 			case STSORT_SRCPT:
1457 				qsort(tstable, tsentry +1,
1458 					sizeof(statetop_t), sort_srcpt);
1459 				break;
1460 			case STSORT_DSTIP:
1461 				qsort(tstable, tsentry + 1,
1462 				      sizeof(statetop_t), sort_dstip);
1463 				break;
1464 			case STSORT_DSTPT:
1465 				qsort(tstable, tsentry + 1,
1466 				      sizeof(statetop_t), sort_dstpt);
1467 				break;
1468 			default:
1469 				break;
1470 			}
1471 		}
1472 
1473 		/* handle window resizes */
1474 		if (handle_resize) {
1475 			endwin();
1476 			initscr();
1477 			cbreak();
1478 			noecho();
1479 			curs_set(0);
1480 			timeout(0);
1481 			getmaxyx(stdscr, maxy, maxx);
1482 			redraw = 1;
1483 			handle_resize = 0;
1484 		}
1485 
1486 		/* stop program? */
1487 		if (handle_break)
1488 			break;
1489 
1490 		/* print title */
1491 		erase();
1492 		attron(A_BOLD);
1493 		winy = 0;
1494 		move(winy,0);
1495 		snprintf(str1, sizeof(str1), "%s - %s - state top", hostnm, IPL_VERSION);
1496 		for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
1497 			printw(" ");
1498 		printw("%s", str1);
1499 		attroff(A_BOLD);
1500 
1501 		/* just for fun add a clock */
1502 		move(winy, maxx - 8);
1503 		t = time(NULL);
1504 		strftime(str1, 80, "%T", localtime(&t));
1505 		printw("%s\n", str1);
1506 
1507 		/*
1508 		 * print the display filters, this is placed in the loop,
1509 		 * because someday I might add code for changing these
1510 		 * while the programming is running :-)
1511 		 */
1512 		if (sport >= 0)
1513 			snprintf(str1, sizeof(str1), "%s,%d", getip(ver, &saddr), sport);
1514 		else
1515 			snprintf(str1, sizeof(str1), "%s", getip(ver, &saddr));
1516 
1517 		if (dport >= 0)
1518 			snprintf(str2, sizeof(str2), "%s,%d", getip(ver, &daddr), dport);
1519 		else
1520 			snprintf(str2, sizeof(str2), "%s", getip(ver, &daddr));
1521 
1522 		if (protocol < 0)
1523 			strcpy(str3, "any");
1524 		else if ((proto = getprotobynumber(protocol)) != NULL)
1525 			snprintf(str3, sizeof(str3), "%s", proto->p_name);
1526 		else
1527 			snprintf(str3, sizeof(str3), "%d", protocol);
1528 
1529 		switch (sorting)
1530 		{
1531 		case STSORT_PR:
1532 			snprintf(str4, sizeof(str4), "proto");
1533 			break;
1534 		case STSORT_PKTS:
1535 			snprintf(str4, sizeof(str4), "# pkts");
1536 			break;
1537 		case STSORT_BYTES:
1538 			snprintf(str4, sizeof(str4), "# bytes");
1539 			break;
1540 		case STSORT_TTL:
1541 			snprintf(str4, sizeof(str4), "ttl");
1542 			break;
1543 		case STSORT_SRCIP:
1544 			snprintf(str4, sizeof(str4), "src ip");
1545 			break;
1546 		case STSORT_SRCPT:
1547 			snprintf(str4, sizeof(str4), "src port");
1548 			break;
1549 		case STSORT_DSTIP:
1550 			snprintf(str4, sizeof(str4), "dest ip");
1551 			break;
1552 		case STSORT_DSTPT:
1553 			snprintf(str4, sizeof(str4), "dest port");
1554 			break;
1555 		default:
1556 			snprintf(str4, sizeof(str4), "unknown");
1557 			break;
1558 		}
1559 
1560 		if (reverse)
1561 			strcat(str4, " (reverse)");
1562 
1563 		winy += 2;
1564 		move(winy,0);
1565 		printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
1566 		       str1, str2, str3, str4);
1567 
1568 		/*
1569 		 * For an IPv4 IP address we need at most 15 characters,
1570 		 * 4 tuples of 3 digits, separated by 3 dots. Enforce this
1571 		 * length, so the columns do not change positions based
1572 		 * on the size of the IP address. This length makes the
1573 		 * output fit in a 80 column terminal.
1574 		 * We are lacking a good solution for IPv6 addresses (that
1575 		 * can be longer that 15 characters), so we do not enforce
1576 		 * a maximum on the IP field size.
1577 		 */
1578 		if (srclen < 15)
1579 			srclen = 15;
1580 		if (dstlen < 15)
1581 			dstlen = 15;
1582 
1583 		/* print column description */
1584 		winy += 2;
1585 		move(winy,0);
1586 		attron(A_BOLD);
1587 		printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
1588 		       srclen + 6, "Source IP", dstlen + 6, "Destination IP",
1589 		       "ST", "PR", "#pkts", "#bytes", "ttl");
1590 		attroff(A_BOLD);
1591 
1592 		/* print all the entries */
1593 		tp = tstable;
1594 		if (reverse)
1595 			tp += tsentry;
1596 
1597 		if (tsentry > maxy - 6)
1598 			tsentry = maxy - 6;
1599 		for (i = 0; i <= tsentry; i++) {
1600 			/* print src/dest and port */
1601 			if ((tp->st_p == IPPROTO_TCP) ||
1602 			    (tp->st_p == IPPROTO_UDP)) {
1603 				snprintf(str1, sizeof(str1), "%s,%hu",
1604 					getip(tp->st_v, &tp->st_src),
1605 					ntohs(tp->st_sport));
1606 				snprintf(str2, sizeof(str2), "%s,%hu",
1607 					getip(tp->st_v, &tp->st_dst),
1608 					ntohs(tp->st_dport));
1609 			} else {
1610 				snprintf(str1, sizeof(str1), "%s", getip(tp->st_v,
1611 				    &tp->st_src));
1612 				snprintf(str2, sizeof(str2), "%s", getip(tp->st_v,
1613 				    &tp->st_dst));
1614 			}
1615 			winy++;
1616 			move(winy, 0);
1617 			printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
1618 
1619 			/* print state */
1620 			snprintf(str1, sizeof(str1), "%X/%X", tp->st_state[0],
1621 				tp->st_state[1]);
1622 			printw(" %3s", str1);
1623 
1624 			/* print protocol */
1625 			proto = getprotobynumber(tp->st_p);
1626 			if (proto) {
1627 				strncpy(str1, proto->p_name, 4);
1628 				str1[4] = '\0';
1629 			} else {
1630 				snprintf(str1, sizeof(str1), "%d", tp->st_p);
1631 			}
1632 			/* just print icmp for IPv6-ICMP */
1633 			if (tp->st_p == IPPROTO_ICMPV6)
1634 				strcpy(str1, "icmp");
1635 			printw(" %4s", str1);
1636 
1637 			/* print #pkt/#bytes */
1638 #ifdef	USE_QUAD_T
1639 			printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
1640 				(unsigned long long) tp->st_bytes);
1641 #else
1642 			printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
1643 #endif
1644 			printw(" %9s", ttl_to_string(tp->st_age));
1645 
1646 			if (reverse)
1647 				tp--;
1648 			else
1649 				tp++;
1650 		}
1651 
1652 		/* screen data structure is filled, now update the screen */
1653 		if (redraw)
1654 			clearok(stdscr,1);
1655 
1656 		if (refresh() == ERR)
1657 			break;
1658 		if (redraw) {
1659 			clearok(stdscr,0);
1660 			redraw = 0;
1661 		}
1662 
1663 		/* wait for key press or a 1 second time out period */
1664 		selecttimeout.tv_sec = refreshtime;
1665 		selecttimeout.tv_usec = 0;
1666 		FD_ZERO(&readfd);
1667 		FD_SET(0, &readfd);
1668 		select(1, &readfd, NULL, NULL, &selecttimeout);
1669 
1670 		/* if key pressed, read all waiting keys */
1671 		if (FD_ISSET(0, &readfd)) {
1672 			c = wgetch(stdscr);
1673 			if (c == ERR)
1674 				continue;
1675 
1676 			if (ISALPHA(c) && ISUPPER(c))
1677 				c = TOLOWER(c);
1678 			if (c == 'l') {
1679 				redraw = 1;
1680 			} else if (c == 'q') {
1681 				break;
1682 			} else if (c == 'r') {
1683 				reverse = !reverse;
1684 			} else if (c == 'b') {
1685 				forward = 0;
1686 			} else if (c == 'f') {
1687 				forward = 1;
1688 			} else if (c == 's') {
1689 				if (++sorting > STSORT_MAX)
1690 					sorting = 0;
1691 			}
1692 		}
1693 	} /* while */
1694 
1695 out:
1696 	printw("\n");
1697 	curs_set(1);
1698 	/* nocbreak(); XXX - endwin() should make this redundant */
1699 	endwin();
1700 
1701 	free(tstable);
1702 	if (ret != 0)
1703 		perror(errstr);
1704 }
1705 #endif
1706 
1707 
1708 /*
1709  * Show fragment cache information that's held in the kernel.
1710  */
1711 static void showfrstates(ipfrstat_t *ifsp, u_long ticks)
1712 {
1713 	struct ipfr *ipfrtab[IPFT_SIZE], ifr;
1714 	int i;
1715 
1716 	/*
1717 	 * print out the numeric statistics
1718 	 */
1719 	PRINTF("IP fragment states:\n%lu\tnew\n%lu\texpired\n%lu\thits\n",
1720 		ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
1721 	PRINTF("%lu\tretrans\n%lu\ttoo short\n",
1722 		ifsp->ifs_retrans0, ifsp->ifs_short);
1723 	PRINTF("%lu\tno memory\n%lu\talready exist\n",
1724 		ifsp->ifs_nomem, ifsp->ifs_exists);
1725 	PRINTF("%lu\tinuse\n", ifsp->ifs_inuse);
1726 	PRINTF("\n");
1727 
1728 	if (live_kernel == 0) {
1729 		if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table,
1730 			    sizeof(ipfrtab)))
1731 			return;
1732 	}
1733 
1734 	/*
1735 	 * Print out the contents (if any) of the fragment cache table.
1736 	 */
1737 	if (live_kernel == 1) {
1738 		do {
1739 			if (fetchfrag(ipf_fd, IPFGENITER_FRAG, &ifr) != 0)
1740 				break;
1741 			if (ifr.ipfr_ifp == NULL)
1742 				break;
1743 			ifr.ipfr_ttl -= ticks;
1744 			printfraginfo("", &ifr);
1745 		} while (ifr.ipfr_next != NULL);
1746 	} else {
1747 		for (i = 0; i < IPFT_SIZE; i++)
1748 			while (ipfrtab[i] != NULL) {
1749 				if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1750 					    sizeof(ifr)) == -1)
1751 					break;
1752 				printfraginfo("", &ifr);
1753 				ipfrtab[i] = ifr.ipfr_next;
1754 			}
1755 	}
1756 	/*
1757 	 * Print out the contents (if any) of the NAT fragment cache table.
1758 	 */
1759 
1760 	if (live_kernel == 0) {
1761 		if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,
1762 			    sizeof(ipfrtab)))
1763 			return;
1764 	}
1765 
1766 	if (live_kernel == 1) {
1767 		do {
1768 			if (fetchfrag(nat_fd, IPFGENITER_NATFRAG, &ifr) != 0)
1769 				break;
1770 			if (ifr.ipfr_ifp == NULL)
1771 				break;
1772 			ifr.ipfr_ttl -= ticks;
1773 			printfraginfo("NAT: ", &ifr);
1774 		} while (ifr.ipfr_next != NULL);
1775 	} else {
1776 		for (i = 0; i < IPFT_SIZE; i++)
1777 			while (ipfrtab[i] != NULL) {
1778 				if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1779 					    sizeof(ifr)) == -1)
1780 					break;
1781 				printfraginfo("NAT: ", &ifr);
1782 				ipfrtab[i] = ifr.ipfr_next;
1783 			}
1784 	}
1785 }
1786 
1787 
1788 /*
1789  * Show stats on how auth within IPFilter has been used
1790  */
1791 static void showauthstates(ipf_authstat_t *asp)
1792 {
1793 	frauthent_t *frap, fra;
1794 	ipfgeniter_t auth;
1795 	ipfobj_t obj;
1796 
1797 	obj.ipfo_rev = IPFILTER_VERSION;
1798 	obj.ipfo_type = IPFOBJ_GENITER;
1799 	obj.ipfo_size = sizeof(auth);
1800 	obj.ipfo_ptr = &auth;
1801 
1802 	auth.igi_type = IPFGENITER_AUTH;
1803 	auth.igi_nitems = 1;
1804 	auth.igi_data = &fra;
1805 
1806 #ifdef	USE_QUAD_T
1807 	printf("Authorisation hits: %"PRIu64"\tmisses %"PRIu64"\n",
1808 		(unsigned long long) asp->fas_hits,
1809 		(unsigned long long) asp->fas_miss);
1810 #else
1811 	printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
1812 		asp->fas_miss);
1813 #endif
1814 	printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
1815 		asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
1816 		asp->fas_sendok);
1817 	printf("queok %ld\nquefail %ld\nexpire %ld\n",
1818 		asp->fas_queok, asp->fas_quefail, asp->fas_expire);
1819 
1820 	frap = asp->fas_faelist;
1821 	while (frap) {
1822 		if (live_kernel == 1) {
1823 			if (ioctl(auth_fd, SIOCGENITER, &obj))
1824 				break;
1825 		} else {
1826 			if (kmemcpy((char *)&fra, (u_long)frap,
1827 				    sizeof(fra)) == -1)
1828 				break;
1829 		}
1830 		printf("age %ld\t", fra.fae_age);
1831 		printfr(&fra.fae_fr, ioctl);
1832 		frap = fra.fae_next;
1833 	}
1834 }
1835 
1836 
1837 /*
1838  * Display groups used for each of filter rules, accounting rules and
1839  * authentication, separately.
1840  */
1841 static void showgroups(struct friostat	*fiop)
1842 {
1843 	static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
1844 	static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH };
1845 	frgroup_t *fp, grp;
1846 	int on, off, i;
1847 
1848 	on = fiop->f_active;
1849 	off = 1 - on;
1850 
1851 	for (i = 0; i < 3; i++) {
1852 		printf("%s groups (active):\n", gnames[i]);
1853 		for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL;
1854 		     fp = grp.fg_next)
1855 			if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1856 				break;
1857 			else
1858 				printf("%s\n", grp.fg_name);
1859 		printf("%s groups (inactive):\n", gnames[i]);
1860 		for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL;
1861 		     fp = grp.fg_next)
1862 			if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1863 				break;
1864 			else
1865 				printf("%s\n", grp.fg_name);
1866 	}
1867 }
1868 
1869 
1870 static void parse_ipportstr(const char *argument, i6addr_t *ip, int *port)
1871 {
1872 	char *s, *comma;
1873 	int ok = 0;
1874 
1875 	/* make working copy of argument, Theoretically you must be able
1876 	 * to write to optarg, but that seems very ugly to me....
1877 	 */
1878 	s = strdup(argument);
1879 	if (s == NULL)
1880 		return;
1881 
1882 	/* get port */
1883 	if ((comma = strchr(s, ',')) != NULL) {
1884 		if (!strcasecmp(comma + 1, "any")) {
1885 			*port = -1;
1886 		} else if (!sscanf(comma + 1, "%d", port) ||
1887 			   (*port < 0) || (*port > 65535)) {
1888 			fprintf(stderr, "Invalid port specification in %s\n",
1889 				argument);
1890 			free(s);
1891 			exit(-2);
1892 		}
1893 		*comma = '\0';
1894 	}
1895 
1896 
1897 	/* get ip address */
1898 	if (!strcasecmp(s, "any")) {
1899 		ip->in4.s_addr = INADDR_ANY;
1900 		ok = 1;
1901 #ifdef	USE_INET6
1902 		ip->in6 = in6addr_any;
1903 	} else if (use_inet6 && !use_inet4 && inet_pton(AF_INET6, s, &ip->in6)) {
1904 		ok = 1;
1905 #endif
1906 	} else if (inet_aton(s, &ip->in4))
1907 		ok = 1;
1908 
1909 	if (ok == 0) {
1910 		fprintf(stderr, "Invalid IP address: %s\n", s);
1911 		free(s);
1912 		exit(-2);
1913 	}
1914 
1915 	/* free allocated memory */
1916 	free(s);
1917 }
1918 
1919 
1920 #ifdef STATETOP
1921 static void sig_resize(int s)
1922 {
1923 	handle_resize = 1;
1924 }
1925 
1926 static void sig_break(int s)
1927 {
1928 	handle_break = 1;
1929 }
1930 
1931 static char *getip(int v, i6addr_t *addr)
1932 {
1933 #ifdef  USE_INET6
1934 	static char hostbuf[MAXHOSTNAMELEN+1];
1935 #endif
1936 
1937 	if (v == 0)
1938 		return ("any");
1939 
1940 	if (v == 4)
1941 		return (inet_ntoa(addr->in4));
1942 
1943 #ifdef  USE_INET6
1944 	(void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1);
1945 	hostbuf[MAXHOSTNAMELEN] = '\0';
1946 	return (hostbuf);
1947 #else
1948 	return ("IPv6");
1949 #endif
1950 }
1951 
1952 
1953 static char *ttl_to_string(long int ttl)
1954 {
1955 	static char ttlbuf[STSTRSIZE];
1956 	int hours, minutes, seconds;
1957 
1958 	/* ttl is in half seconds */
1959 	ttl /= 2;
1960 
1961 	hours = ttl / 3600;
1962 	ttl = ttl % 3600;
1963 	minutes = ttl / 60;
1964 	seconds = ttl % 60;
1965 
1966 	if (hours > 0)
1967 		snprintf(ttlbuf, sizeof(ttlbuf), "%2d:%02d:%02d", hours, minutes, seconds);
1968 	else
1969 		snprintf(ttlbuf, sizeof(ttlbuf), "%2d:%02d", minutes, seconds);
1970 	return (ttlbuf);
1971 }
1972 
1973 
1974 static int sort_pkts(const void *a, const void *b)
1975 {
1976 
1977 	register const statetop_t *ap = a;
1978 	register const statetop_t *bp = b;
1979 
1980 	if (ap->st_pkts == bp->st_pkts)
1981 		return (0);
1982 	else if (ap->st_pkts < bp->st_pkts)
1983 		return (1);
1984 	return (-1);
1985 }
1986 
1987 
1988 static int sort_bytes(const void *a, const void *b)
1989 {
1990 	register const statetop_t *ap = a;
1991 	register const statetop_t *bp = b;
1992 
1993 	if (ap->st_bytes == bp->st_bytes)
1994 		return (0);
1995 	else if (ap->st_bytes < bp->st_bytes)
1996 		return (1);
1997 	return (-1);
1998 }
1999 
2000 
2001 static int sort_p(const void *a, const void *b)
2002 {
2003 	register const statetop_t *ap = a;
2004 	register const statetop_t *bp = b;
2005 
2006 	if (ap->st_p == bp->st_p)
2007 		return (0);
2008 	else if (ap->st_p < bp->st_p)
2009 		return (1);
2010 	return (-1);
2011 }
2012 
2013 
2014 static int sort_ttl(const void *a, const void *b)
2015 {
2016 	register const statetop_t *ap = a;
2017 	register const statetop_t *bp = b;
2018 
2019 	if (ap->st_age == bp->st_age)
2020 		return (0);
2021 	else if (ap->st_age < bp->st_age)
2022 		return (1);
2023 	return (-1);
2024 }
2025 
2026 static int sort_srcip(const void *a, const void *b)
2027 {
2028 	register const statetop_t *ap = a;
2029 	register const statetop_t *bp = b;
2030 
2031 #ifdef USE_INET6
2032 	if (use_inet6 && !use_inet4) {
2033 		if (IP6_EQ(&ap->st_src, &bp->st_src))
2034 			return (0);
2035 		else if (IP6_GT(&ap->st_src, &bp->st_src))
2036 			return (1);
2037 	} else
2038 #endif
2039 	{
2040 		if (ntohl(ap->st_src.in4.s_addr) ==
2041 		    ntohl(bp->st_src.in4.s_addr))
2042 			return (0);
2043 		else if (ntohl(ap->st_src.in4.s_addr) >
2044 		         ntohl(bp->st_src.in4.s_addr))
2045 			return (1);
2046 	}
2047 	return (-1);
2048 }
2049 
2050 static int sort_srcpt(const void *a, const void *b)
2051 {
2052 	register const statetop_t *ap = a;
2053 	register const statetop_t *bp = b;
2054 
2055 	if (htons(ap->st_sport) == htons(bp->st_sport))
2056 		return (0);
2057 	else if (htons(ap->st_sport) > htons(bp->st_sport))
2058 		return (1);
2059 	return (-1);
2060 }
2061 
2062 static int sort_dstip(const void *a, const void *b)
2063 {
2064 	register const statetop_t *ap = a;
2065 	register const statetop_t *bp = b;
2066 
2067 #ifdef USE_INET6
2068 	if (use_inet6 && !use_inet4) {
2069 		if (IP6_EQ(&ap->st_dst, &bp->st_dst))
2070 			return (0);
2071 		else if (IP6_GT(&ap->st_dst, &bp->st_dst))
2072 			return (1);
2073 	} else
2074 #endif
2075 	{
2076 		if (ntohl(ap->st_dst.in4.s_addr) ==
2077 		    ntohl(bp->st_dst.in4.s_addr))
2078 			return (0);
2079 		else if (ntohl(ap->st_dst.in4.s_addr) >
2080 		         ntohl(bp->st_dst.in4.s_addr))
2081 			return (1);
2082 	}
2083 	return (-1);
2084 }
2085 
2086 static int sort_dstpt(const void *a, const void *b)
2087 {
2088 	register const statetop_t *ap = a;
2089 	register const statetop_t *bp = b;
2090 
2091 	if (htons(ap->st_dport) == htons(bp->st_dport))
2092 		return (0);
2093 	else if (htons(ap->st_dport) > htons(bp->st_dport))
2094 		return (1);
2095 	return (-1);
2096 }
2097 
2098 #endif
2099 
2100 
2101 ipstate_t *fetchstate(ipstate_t *src, ipstate_t *dst)
2102 {
2103 
2104 	if (live_kernel == 1) {
2105 		ipfgeniter_t state;
2106 		ipfobj_t obj;
2107 
2108 		obj.ipfo_rev = IPFILTER_VERSION;
2109 		obj.ipfo_type = IPFOBJ_GENITER;
2110 		obj.ipfo_size = sizeof(state);
2111 		obj.ipfo_ptr = &state;
2112 
2113 		state.igi_type = IPFGENITER_STATE;
2114 		state.igi_nitems = 1;
2115 		state.igi_data = dst;
2116 
2117 		if (ioctl(state_fd, SIOCGENITER, &obj) != 0)
2118 			return (NULL);
2119 		if (dst->is_next == NULL) {
2120 			int n = IPFGENITER_STATE;
2121 			(void) ioctl(ipf_fd,SIOCIPFDELTOK, &n);
2122 		}
2123 	} else {
2124 		if (kmemcpy((char *)dst, (u_long)src, sizeof(*dst)))
2125 			return (NULL);
2126 	}
2127 	return (dst);
2128 }
2129 
2130 
2131 static int fetchfrag( int fd, int type, ipfr_t *frp)
2132 {
2133 	ipfgeniter_t frag;
2134 	ipfobj_t obj;
2135 
2136 	obj.ipfo_rev = IPFILTER_VERSION;
2137 	obj.ipfo_type = IPFOBJ_GENITER;
2138 	obj.ipfo_size = sizeof(frag);
2139 	obj.ipfo_ptr = &frag;
2140 
2141 	frag.igi_type = type;
2142 	frag.igi_nitems = 1;
2143 	frag.igi_data = frp;
2144 
2145 	if (ioctl(fd, SIOCGENITER, &obj))
2146 		return (EFAULT);
2147 	return (0);
2148 }
2149 
2150 
2151 static int state_matcharray(ipstate_t *stp, int *array)
2152 {
2153 	int i, n, *x, rv, p;
2154 	ipfexp_t *e;
2155 
2156 	rv = 0;
2157 
2158 	for (n = array[0], x = array + 1; n > 0; x += e->ipfe_size) {
2159 		e = (ipfexp_t *)x;
2160 		if (e->ipfe_cmd == IPF_EXP_END)
2161 			break;
2162 		n -= e->ipfe_size;
2163 
2164 		rv = 0;
2165 		/*
2166 		 * The upper 16 bits currently store the protocol value.
2167 		 * This is currently used with TCP and UDP port compares and
2168 		 * allows "tcp.port = 80" without requiring an explicit
2169 		 " "ip.pr = tcp" first.
2170 		 */
2171 		p = e->ipfe_cmd >> 16;
2172 		if ((p != 0) && (p != stp->is_p))
2173 			break;
2174 
2175 		switch (e->ipfe_cmd)
2176 		{
2177 		case IPF_EXP_IP_PR :
2178 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2179 				rv |= (stp->is_p == e->ipfe_arg0[i]);
2180 			}
2181 			break;
2182 
2183 		case IPF_EXP_IP_SRCADDR :
2184 			if (stp->is_v != 4)
2185 				break;
2186 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2187 				rv |= ((stp->is_saddr &
2188 					e->ipfe_arg0[i * 2 + 1]) ==
2189 				       e->ipfe_arg0[i * 2]);
2190 			}
2191 			break;
2192 
2193 		case IPF_EXP_IP_DSTADDR :
2194 			if (stp->is_v != 4)
2195 				break;
2196 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2197 				rv |= ((stp->is_daddr &
2198 					e->ipfe_arg0[i * 2 + 1]) ==
2199 				       e->ipfe_arg0[i * 2]);
2200 			}
2201 			break;
2202 
2203 		case IPF_EXP_IP_ADDR :
2204 			if (stp->is_v != 4)
2205 				break;
2206 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2207 				rv |= ((stp->is_saddr &
2208 					e->ipfe_arg0[i * 2 + 1]) ==
2209 				       e->ipfe_arg0[i * 2]) ||
2210 				      ((stp->is_daddr &
2211 					e->ipfe_arg0[i * 2 + 1]) ==
2212 				       e->ipfe_arg0[i * 2]);
2213 			}
2214 			break;
2215 
2216 #ifdef USE_INET6
2217 		case IPF_EXP_IP6_SRCADDR :
2218 			if (stp->is_v != 6)
2219 				break;
2220 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2221 				rv |= IP6_MASKEQ(&stp->is_src,
2222 						 &e->ipfe_arg0[i * 8 + 4],
2223 						 &e->ipfe_arg0[i * 8]);
2224 			}
2225 			break;
2226 
2227 		case IPF_EXP_IP6_DSTADDR :
2228 			if (stp->is_v != 6)
2229 				break;
2230 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2231 				rv |= IP6_MASKEQ(&stp->is_dst,
2232 						 &e->ipfe_arg0[i * 8 + 4],
2233 						 &e->ipfe_arg0[i * 8]);
2234 			}
2235 			break;
2236 
2237 		case IPF_EXP_IP6_ADDR :
2238 			if (stp->is_v != 6)
2239 				break;
2240 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2241 				rv |= IP6_MASKEQ(&stp->is_src,
2242 						 &e->ipfe_arg0[i * 8 + 4],
2243 						 &e->ipfe_arg0[i * 8]) ||
2244 				      IP6_MASKEQ(&stp->is_dst,
2245 						 &e->ipfe_arg0[i * 8 + 4],
2246 						 &e->ipfe_arg0[i * 8]);
2247 			}
2248 			break;
2249 #endif
2250 
2251 		case IPF_EXP_UDP_PORT :
2252 		case IPF_EXP_TCP_PORT :
2253 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2254 				rv |= (stp->is_sport == e->ipfe_arg0[i]) ||
2255 				      (stp->is_dport == e->ipfe_arg0[i]);
2256 			}
2257 			break;
2258 
2259 		case IPF_EXP_UDP_SPORT :
2260 		case IPF_EXP_TCP_SPORT :
2261 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2262 				rv |= (stp->is_sport == e->ipfe_arg0[i]);
2263 			}
2264 			break;
2265 
2266 		case IPF_EXP_UDP_DPORT :
2267 		case IPF_EXP_TCP_DPORT :
2268 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2269 				rv |= (stp->is_dport == e->ipfe_arg0[i]);
2270 			}
2271 			break;
2272 
2273 		case IPF_EXP_IDLE_GT :
2274 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2275 				rv |= (stp->is_die < e->ipfe_arg0[i]);
2276 			}
2277 			break;
2278 
2279 		case IPF_EXP_TCP_STATE :
2280 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2281 				rv |= (stp->is_state[0] == e->ipfe_arg0[i]) ||
2282 				      (stp->is_state[1] == e->ipfe_arg0[i]);
2283 			}
2284 			break;
2285 		}
2286 		rv ^= e->ipfe_not;
2287 
2288 		if (rv == 0)
2289 			break;
2290 	}
2291 
2292 	return (rv);
2293 }
2294 
2295 
2296 static void showtqtable_live(int fd)
2297 {
2298 	ipftq_t table[IPF_TCP_NSTATES];
2299 	ipfobj_t obj;
2300 
2301 	bzero((char *)&obj, sizeof(obj));
2302 	obj.ipfo_rev = IPFILTER_VERSION;
2303 	obj.ipfo_size = sizeof(table);
2304 	obj.ipfo_ptr = (void *)table;
2305 	obj.ipfo_type = IPFOBJ_STATETQTAB;
2306 
2307 	if (ioctl(fd, SIOCGTQTAB, &obj) == 0) {
2308 		printtqtable(table);
2309 	}
2310 }
2311