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