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