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