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