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