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