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