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