1/*	$FreeBSD$	*/
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 const char sccsid[] = "@(#)fils.c	1.21 4/20/96 (C) 1993-2000 Darren Reed";
75static const char rcsid[] = "@(#)$Id$";
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	frgroup_t *g;
803	ipfobj_t obj;
804	int rules;
805	int num;
806
807	rules = 0;
808
809	rule.iri_inout = out;
810	rule.iri_active = set;
811	rule.iri_rule = &fb;
812	rule.iri_nrules = 1;
813	if (group != NULL)
814		strncpy(rule.iri_group, group, FR_GROUPLEN);
815	else
816		rule.iri_group[0] = '\0';
817
818	bzero((char *)&zero, sizeof(zero));
819
820	bzero((char *)&obj, sizeof(obj));
821	obj.ipfo_rev = IPFILTER_VERSION;
822	obj.ipfo_type = IPFOBJ_IPFITER;
823	obj.ipfo_size = sizeof(rule);
824	obj.ipfo_ptr = &rule;
825
826	while (rule.iri_rule != NULL) {
827		u_long array[1000];
828
829		memset(array, 0xff, sizeof(array));
830		fp = (frentry_t *)array;
831		rule.iri_rule = fp;
832		if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) {
833			ipferror(ipf_fd, "ioctl(SIOCIPFITER)");
834			num = IPFGENITER_IPF;
835			(void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
836			return rules;
837		}
838		if (bcmp(fp, &zero, sizeof(zero)) == 0)
839			break;
840		if (rule.iri_rule == NULL)
841			break;
842#ifdef USE_INET6
843		if (use_inet6 != 0) {
844			if (fp->fr_family != 0 && fp->fr_family != AF_INET6)
845				continue;
846		} else
847#endif
848		{
849			if (fp->fr_family != 0 && fp->fr_family != AF_INET)
850				continue;
851		}
852		if (fp->fr_data != NULL)
853			fp->fr_data = (char *)fp + fp->fr_size;
854
855		rules++;
856
857		if (opts & (OPT_HITS|OPT_DEBUG))
858#ifdef	USE_QUAD_T
859			PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_hits);
860#else
861			PRINTF("%lu ", fp->fr_hits);
862#endif
863		if (opts & (OPT_ACCNT|OPT_DEBUG))
864#ifdef	USE_QUAD_T
865			PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_bytes);
866#else
867			PRINTF("%lu ", fp->fr_bytes);
868#endif
869		if (opts & OPT_SHOWLINENO)
870			PRINTF("@%d ", rules);
871
872		if (fp->fr_die != 0)
873			fp->fr_die -= fiop->f_ticks;
874
875		printfr(fp, ioctl);
876		if (opts & OPT_DEBUG) {
877			binprint(fp, fp->fr_size);
878			if (fp->fr_data != NULL && fp->fr_dsize > 0)
879				binprint(fp->fr_data, fp->fr_dsize);
880		}
881		if (fp->fr_grhead != -1) {
882			for (g = grtop; g != NULL; g = g->fg_next) {
883				if (!strncmp(fp->fr_names + fp->fr_grhead,
884					     g->fg_name,
885					     FR_GROUPLEN))
886					break;
887			}
888			if (g == NULL) {
889				g = calloc(1, sizeof(*g));
890
891				if (g != NULL) {
892					strncpy(g->fg_name,
893						fp->fr_names + fp->fr_grhead,
894						FR_GROUPLEN);
895					if (grtop == NULL) {
896						grtop = g;
897						grtail = g;
898					} else {
899						grtail->fg_next = g;
900						grtail = g;
901					}
902				}
903			}
904		}
905		if (fp->fr_type == FR_T_CALLFUNC) {
906			rules += printlivelist(fiop, out, set, fp->fr_data,
907					       group, "# callfunc: ");
908		}
909	}
910
911	num = IPFGENITER_IPF;
912	(void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
913
914	return rules;
915}
916
917
918static void printdeadlist(fiop, out, set, fp, group, comment)
919	friostat_t *fiop;
920	int out, set;
921	frentry_t *fp;
922	char *group, *comment;
923{
924	frgroup_t *grtop, *grtail, *g;
925	struct	frentry	fb;
926	char	*data;
927	u_32_t	type;
928	int	n;
929
930	fb.fr_next = fp;
931	n = 0;
932	grtop = NULL;
933	grtail = NULL;
934
935	for (n = 1; fp; fp = fb.fr_next, n++) {
936		if (kmemcpy((char *)&fb, (u_long)fb.fr_next,
937			    fb.fr_size) == -1) {
938			perror("kmemcpy");
939			return;
940		}
941		fp = &fb;
942		if (use_inet6 != 0) {
943			if (fp->fr_family != 0 && fp->fr_family != 6)
944				continue;
945		} else {
946			if (fp->fr_family != 0 && fp->fr_family != 4)
947				continue;
948		}
949
950		data = NULL;
951		type = fb.fr_type & ~FR_T_BUILTIN;
952		if (type == FR_T_IPF || type == FR_T_BPFOPC) {
953			if (fb.fr_dsize) {
954				data = malloc(fb.fr_dsize);
955
956				if (kmemcpy(data, (u_long)fb.fr_data,
957					    fb.fr_dsize) == -1) {
958					perror("kmemcpy");
959					return;
960				}
961				fb.fr_data = data;
962			}
963		}
964
965		if (opts & OPT_HITS)
966#ifdef	USE_QUAD_T
967			PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_hits);
968#else
969			PRINTF("%lu ", fb.fr_hits);
970#endif
971		if (opts & OPT_ACCNT)
972#ifdef	USE_QUAD_T
973			PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_bytes);
974#else
975			PRINTF("%lu ", fb.fr_bytes);
976#endif
977		if (opts & OPT_SHOWLINENO)
978			PRINTF("@%d ", n);
979
980		printfr(fp, ioctl);
981		if (opts & OPT_DEBUG) {
982			binprint(fp, fp->fr_size);
983			if (fb.fr_data != NULL && fb.fr_dsize > 0)
984				binprint(fb.fr_data, fb.fr_dsize);
985		}
986		if (data != NULL)
987			free(data);
988		if (fb.fr_grhead != -1) {
989			g = calloc(1, sizeof(*g));
990
991			if (g != NULL) {
992				strncpy(g->fg_name, fb.fr_names + fb.fr_grhead,
993					FR_GROUPLEN);
994				if (grtop == NULL) {
995					grtop = g;
996					grtail = g;
997				} else {
998					grtail->fg_next = g;
999					grtail = g;
1000				}
1001			}
1002		}
1003		if (type == FR_T_CALLFUNC) {
1004			printdeadlist(fiop, out, set, fb.fr_data, group,
1005				      "# callfunc: ");
1006		}
1007	}
1008
1009	while ((g = grtop) != NULL) {
1010		printdeadlist(fiop, out, set, NULL, g->fg_name, comment);
1011		grtop = g->fg_next;
1012		free(g);
1013	}
1014}
1015
1016/*
1017 * print out all of the asked for rule sets, using the stats struct as
1018 * the base from which to get the pointers.
1019 */
1020static	void	showlist(fiop)
1021	struct	friostat	*fiop;
1022{
1023	struct	frentry	*fp = NULL;
1024	int	i, set;
1025
1026	set = fiop->f_active;
1027	if (opts & OPT_INACTIVE)
1028		set = 1 - set;
1029	if (opts & OPT_ACCNT) {
1030		if (opts & OPT_OUTQUE) {
1031			i = F_ACOUT;
1032			fp = (struct frentry *)fiop->f_acctout[set];
1033		} else if (opts & OPT_INQUE) {
1034			i = F_ACIN;
1035			fp = (struct frentry *)fiop->f_acctin[set];
1036		} else {
1037			FPRINTF(stderr, "No -i or -o given with -a\n");
1038			return;
1039		}
1040	} else {
1041		if (opts & OPT_OUTQUE) {
1042			i = F_OUT;
1043			fp = (struct frentry *)fiop->f_fout[set];
1044		} else if (opts & OPT_INQUE) {
1045			i = F_IN;
1046			fp = (struct frentry *)fiop->f_fin[set];
1047		} else
1048			return;
1049	}
1050	if (opts & OPT_DEBUG)
1051		FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
1052
1053	if (opts & OPT_DEBUG)
1054		PRINTF("fp %p set %d\n", fp, set);
1055
1056	if (live_kernel == 1) {
1057		int printed;
1058
1059		printed = printlivelist(fiop, i, set, fp, NULL, NULL);
1060		if (printed == 0) {
1061			FPRINTF(stderr, "# empty list for %s%s\n",
1062			        (opts & OPT_INACTIVE) ? "inactive " : "",
1063							filters[i]);
1064		}
1065	} else {
1066		if (!fp) {
1067			FPRINTF(stderr, "# empty list for %s%s\n",
1068			        (opts & OPT_INACTIVE) ? "inactive " : "",
1069							filters[i]);
1070		} else {
1071			printdeadlist(fiop, i, set, fp, NULL, NULL);
1072		}
1073	}
1074}
1075
1076
1077/*
1078 * Display ipfilter stateful filtering information
1079 */
1080static void showipstates(ipsp, filter)
1081	ips_stat_t *ipsp;
1082	int *filter;
1083{
1084	ipstate_t *is;
1085	int i;
1086
1087	/*
1088	 * If a list of states hasn't been asked for, only print out stats
1089	 */
1090	if (!(opts & OPT_SHOWLIST)) {
1091		showstatestats(ipsp);
1092		return;
1093	}
1094
1095	if ((state_fields != NULL) && (nohdrfields == 0)) {
1096		for (i = 0; state_fields[i].w_value != 0; i++) {
1097			printfieldhdr(statefields, state_fields + i);
1098			if (state_fields[i + 1].w_value != 0)
1099				printf("\t");
1100		}
1101		printf("\n");
1102	}
1103
1104	/*
1105	 * Print out all the state information currently held in the kernel.
1106	 */
1107	for (is = ipsp->iss_list; is != NULL; ) {
1108		ipstate_t ips;
1109
1110		is = fetchstate(is, &ips);
1111
1112		if (is == NULL)
1113			break;
1114
1115		is = ips.is_next;
1116		if ((filter != NULL) &&
1117		    (state_matcharray(&ips, filter) == 0)) {
1118			continue;
1119		}
1120		if (state_fields != NULL) {
1121			for (i = 0; state_fields[i].w_value != 0; i++) {
1122				printstatefield(&ips, state_fields[i].w_value);
1123				if (state_fields[i + 1].w_value != 0)
1124					printf("\t");
1125			}
1126			printf("\n");
1127		} else {
1128			printstate(&ips, opts, ipsp->iss_ticks);
1129		}
1130	}
1131}
1132
1133
1134static void showstatestats(ipsp)
1135	ips_stat_t *ipsp;
1136{
1137	int minlen, maxlen, totallen;
1138	ipftable_t table;
1139	u_int *buckets;
1140	ipfobj_t obj;
1141	int i, sz;
1142
1143	/*
1144	 * If a list of states hasn't been asked for, only print out stats
1145	 */
1146
1147	sz = sizeof(*buckets) * ipsp->iss_state_size;
1148	buckets = (u_int *)malloc(sz);
1149
1150	obj.ipfo_rev = IPFILTER_VERSION;
1151	obj.ipfo_type = IPFOBJ_GTABLE;
1152	obj.ipfo_size = sizeof(table);
1153	obj.ipfo_ptr = &table;
1154
1155	table.ita_type = IPFTABLE_BUCKETS;
1156	table.ita_table = buckets;
1157
1158	if (live_kernel == 1) {
1159		if (ioctl(state_fd, SIOCGTABL, &obj) != 0) {
1160			free(buckets);
1161			return;
1162		}
1163	} else {
1164		if (kmemcpy((char *)buckets,
1165			    (u_long)ipsp->iss_bucketlen, sz)) {
1166			free(buckets);
1167			return;
1168		}
1169	}
1170
1171	PRINTF("%u\tactive state table entries\n",ipsp->iss_active);
1172	PRINTF("%lu\tadd bad\n", ipsp->iss_add_bad);
1173	PRINTF("%lu\tadd duplicate\n", ipsp->iss_add_dup);
1174	PRINTF("%lu\tadd locked\n", ipsp->iss_add_locked);
1175	PRINTF("%lu\tadd oow\n", ipsp->iss_add_oow);
1176	PRINTF("%lu\tbucket full\n", ipsp->iss_bucket_full);
1177	PRINTF("%lu\tcheck bad\n", ipsp->iss_check_bad);
1178	PRINTF("%lu\tcheck miss\n", ipsp->iss_check_miss);
1179	PRINTF("%lu\tcheck nattag\n", ipsp->iss_check_nattag);
1180	PRINTF("%lu\tclone nomem\n", ipsp->iss_clone_nomem);
1181	PRINTF("%lu\tcheck notag\n", ipsp->iss_check_notag);
1182	PRINTF("%lu\tcheck success\n", ipsp->iss_hits);
1183	PRINTF("%lu\tcloned\n", ipsp->iss_cloned);
1184	PRINTF("%lu\texpired\n", ipsp->iss_expire);
1185	PRINTF("%lu\tflush all\n", ipsp->iss_flush_all);
1186	PRINTF("%lu\tflush closing\n", ipsp->iss_flush_closing);
1187	PRINTF("%lu\tflush queue\n", ipsp->iss_flush_queue);
1188	PRINTF("%lu\tflush state\n", ipsp->iss_flush_state);
1189	PRINTF("%lu\tflush timeout\n", ipsp->iss_flush_timeout);
1190	PRINTF("%u\thash buckets in use\n", ipsp->iss_inuse);
1191	PRINTF("%lu\tICMP bad\n", ipsp->iss_icmp_bad);
1192	PRINTF("%lu\tICMP banned\n", ipsp->iss_icmp_banned);
1193	PRINTF("%lu\tICMP errors\n", ipsp->iss_icmp_icmperr);
1194	PRINTF("%lu\tICMP head block\n", ipsp->iss_icmp_headblock);
1195	PRINTF("%lu\tICMP hits\n", ipsp->iss_icmp_hits);
1196	PRINTF("%lu\tICMP not query\n",	ipsp->iss_icmp_notquery);
1197	PRINTF("%lu\tICMP short\n", ipsp->iss_icmp_short);
1198	PRINTF("%lu\tICMP too many\n", ipsp->iss_icmp_toomany);
1199	PRINTF("%lu\tICMPv6 errors\n", ipsp->iss_icmp6_icmperr);
1200	PRINTF("%lu\tICMPv6 miss\n", ipsp->iss_icmp6_miss);
1201	PRINTF("%lu\tICMPv6 not info\n", ipsp->iss_icmp6_notinfo);
1202	PRINTF("%lu\tICMPv6 not query\n", ipsp->iss_icmp6_notquery);
1203	PRINTF("%lu\tlog fail\n", ipsp->iss_log_fail);
1204	PRINTF("%lu\tlog ok\n", ipsp->iss_log_ok);
1205	PRINTF("%lu\tlookup interface mismatch\n", ipsp->iss_lookup_badifp);
1206	PRINTF("%lu\tlookup mask mismatch\n", ipsp->iss_miss_mask);
1207	PRINTF("%lu\tlookup port mismatch\n", ipsp->iss_lookup_badport);
1208	PRINTF("%lu\tlookup miss\n", ipsp->iss_lookup_miss);
1209	PRINTF("%lu\tmaximum rule references\n", ipsp->iss_max_ref);
1210	PRINTF("%lu\tmaximum hosts per rule\n", ipsp->iss_max_track);
1211	PRINTF("%lu\tno memory\n", ipsp->iss_nomem);
1212	PRINTF("%lu\tout of window\n", ipsp->iss_oow);
1213	PRINTF("%lu\torphans\n", ipsp->iss_orphan);
1214	PRINTF("%lu\tscan block\n", ipsp->iss_scan_block);
1215	PRINTF("%lu\tstate table maximum reached\n", ipsp->iss_max);
1216	PRINTF("%lu\tTCP closing\n", ipsp->iss_tcp_closing);
1217	PRINTF("%lu\tTCP OOW\n", ipsp->iss_tcp_oow);
1218	PRINTF("%lu\tTCP RST add\n", ipsp->iss_tcp_rstadd);
1219	PRINTF("%lu\tTCP too small\n", ipsp->iss_tcp_toosmall);
1220	PRINTF("%lu\tTCP bad options\n", ipsp->iss_tcp_badopt);
1221	PRINTF("%lu\tTCP removed\n", ipsp->iss_fin);
1222	PRINTF("%lu\tTCP FSM\n", ipsp->iss_tcp_fsm);
1223	PRINTF("%lu\tTCP strict\n", ipsp->iss_tcp_strict);
1224	PRINTF("%lu\tTCP wild\n", ipsp->iss_wild);
1225	PRINTF("%lu\tMicrosoft Windows SACK\n", ipsp->iss_winsack);
1226
1227	PRINTF("State logging %sabled\n", state_logging ? "en" : "dis");
1228
1229	PRINTF("IP states added:\n");
1230	for (i = 0; i < 256; i++) {
1231		if (ipsp->iss_proto[i] != 0) {
1232			struct protoent *proto;
1233
1234			proto = getprotobynumber(i);
1235			PRINTF("%lu", ipsp->iss_proto[i]);
1236			if (proto != NULL)
1237				PRINTF("\t%s\n", proto->p_name);
1238			else
1239				PRINTF("\t%d\n", i);
1240		}
1241	}
1242
1243	PRINTF("\nState table bucket statistics:\n");
1244	PRINTF("%u\tin use\n", ipsp->iss_inuse);
1245
1246	minlen = ipsp->iss_max;
1247	totallen = 0;
1248	maxlen = 0;
1249
1250	for (i = 0; i < ipsp->iss_state_size; i++) {
1251		if (buckets[i] > maxlen)
1252			maxlen = buckets[i];
1253		if (buckets[i] < minlen)
1254			minlen = buckets[i];
1255		totallen += buckets[i];
1256	}
1257
1258	PRINTF("%d\thash efficiency\n",
1259		totallen ? ipsp->iss_inuse * 100 / totallen : 0);
1260	PRINTF("%2.2f%%\tbucket usage\n%u\tminimal length\n",
1261		((float)ipsp->iss_inuse / ipsp->iss_state_size) * 100.0,
1262		minlen);
1263	PRINTF("%u\tmaximal length\n%.3f\taverage length\n",
1264		maxlen,
1265		ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse :
1266				  0.0);
1267
1268#define ENTRIES_PER_LINE 5
1269
1270	if (opts & OPT_VERBOSE) {
1271		PRINTF("\nCurrent bucket sizes :\n");
1272		for (i = 0; i < ipsp->iss_state_size; i++) {
1273			if ((i % ENTRIES_PER_LINE) == 0)
1274				PRINTF("\t");
1275			PRINTF("%4d -> %4u", i, buckets[i]);
1276			if ((i % ENTRIES_PER_LINE) ==
1277			    (ENTRIES_PER_LINE - 1))
1278				PRINTF("\n");
1279			else
1280				PRINTF("  ");
1281		}
1282		PRINTF("\n");
1283	}
1284	PRINTF("\n");
1285
1286	free(buckets);
1287
1288	if (live_kernel == 1) {
1289		showtqtable_live(state_fd);
1290	} else {
1291		printtqtable(ipsp->iss_tcptab);
1292	}
1293}
1294
1295
1296#ifdef STATETOP
1297static int handle_resize = 0, handle_break = 0;
1298
1299static void topipstates(saddr, daddr, sport, dport, protocol, ver,
1300		        refreshtime, topclosed, filter)
1301	i6addr_t saddr;
1302	i6addr_t daddr;
1303	int sport;
1304	int dport;
1305	int protocol;
1306	int ver;
1307	int refreshtime;
1308	int topclosed;
1309	int *filter;
1310{
1311	char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
1312	int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
1313	int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0;
1314	int len, srclen, dstlen, forward = 1, c = 0;
1315	ips_stat_t ipsst, *ipsstp = &ipsst;
1316	int token_type = IPFGENITER_STATE;
1317	statetop_t *tstable = NULL, *tp;
1318	const char *errstr = "";
1319	ipstate_t ips;
1320	ipfobj_t ipfo;
1321	struct timeval selecttimeout;
1322	char hostnm[HOSTNMLEN];
1323	struct protoent *proto;
1324	fd_set readfd;
1325	time_t t;
1326
1327	/* install signal handlers */
1328	signal(SIGINT, sig_break);
1329	signal(SIGQUIT, sig_break);
1330	signal(SIGTERM, sig_break);
1331	signal(SIGWINCH, sig_resize);
1332
1333	/* init ncurses stuff */
1334  	initscr();
1335  	cbreak();
1336  	noecho();
1337	curs_set(0);
1338	timeout(0);
1339	getmaxyx(stdscr, maxy, maxx);
1340
1341	/* init hostname */
1342	gethostname(hostnm, sizeof(hostnm) - 1);
1343	hostnm[sizeof(hostnm) - 1] = '\0';
1344
1345	/* init ipfobj_t stuff */
1346	bzero((caddr_t)&ipfo, sizeof(ipfo));
1347	ipfo.ipfo_rev = IPFILTER_VERSION;
1348	ipfo.ipfo_type = IPFOBJ_STATESTAT;
1349	ipfo.ipfo_size = sizeof(*ipsstp);
1350	ipfo.ipfo_ptr = (void *)ipsstp;
1351
1352	/* repeat until user aborts */
1353	while ( 1 ) {
1354
1355		/* get state table */
1356		bzero((char *)&ipsst, sizeof(ipsst));
1357		if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
1358			errstr = "ioctl(SIOCGETFS)";
1359			ret = -1;
1360			goto out;
1361		}
1362
1363		/* clear the history */
1364		tsentry = -1;
1365
1366		/* reset max str len */
1367		srclen = dstlen = 0;
1368
1369		/* read the state table and store in tstable */
1370		for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
1371
1372			ipsstp->iss_list = fetchstate(ipsstp->iss_list, &ips);
1373			if (ipsstp->iss_list == NULL)
1374				break;
1375
1376			if (ips.is_v != ver)
1377				continue;
1378
1379			if ((filter != NULL) &&
1380			    (state_matcharray(&ips, filter) == 0))
1381				continue;
1382
1383			/* check v4 src/dest addresses */
1384			if (ips.is_v == 4) {
1385				if ((saddr.in4.s_addr != INADDR_ANY &&
1386				     saddr.in4.s_addr != ips.is_saddr) ||
1387				    (daddr.in4.s_addr != INADDR_ANY &&
1388				     daddr.in4.s_addr != ips.is_daddr))
1389					continue;
1390			}
1391#ifdef	USE_INET6
1392			/* check v6 src/dest addresses */
1393			if (ips.is_v == 6) {
1394				if ((IP6_NEQ(&saddr, &in6addr_any) &&
1395				     IP6_NEQ(&saddr, &ips.is_src)) ||
1396				    (IP6_NEQ(&daddr, &in6addr_any) &&
1397				     IP6_NEQ(&daddr, &ips.is_dst)))
1398					continue;
1399			}
1400#endif
1401			/* check protocol */
1402			if (protocol > 0 && protocol != ips.is_p)
1403				continue;
1404
1405			/* check ports if protocol is TCP or UDP */
1406			if (((ips.is_p == IPPROTO_TCP) ||
1407			     (ips.is_p == IPPROTO_UDP)) &&
1408			   (((sport > 0) && (htons(sport) != ips.is_sport)) ||
1409			    ((dport > 0) && (htons(dport) != ips.is_dport))))
1410				continue;
1411
1412			/* show closed TCP sessions ? */
1413			if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
1414			    (ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
1415			    (ips.is_state[1] >= IPF_TCPS_LAST_ACK))
1416				continue;
1417
1418			/*
1419			 * if necessary make room for this state
1420			 * entry
1421			 */
1422			tsentry++;
1423			if (!maxtsentries || tsentry == maxtsentries) {
1424				maxtsentries += STGROWSIZE;
1425				tstable = realloc(tstable,
1426				    maxtsentries * sizeof(statetop_t));
1427				if (tstable == NULL) {
1428					perror("realloc");
1429					exit(-1);
1430				}
1431			}
1432
1433			/* get max src/dest address string length */
1434			len = strlen(getip(ips.is_v, &ips.is_src));
1435			if (srclen < len)
1436				srclen = len;
1437			len = strlen(getip(ips.is_v, &ips.is_dst));
1438			if (dstlen < len)
1439				dstlen = len;
1440
1441			/* fill structure */
1442			tp = tstable + tsentry;
1443			tp->st_src = ips.is_src;
1444			tp->st_dst = ips.is_dst;
1445			tp->st_p = ips.is_p;
1446			tp->st_v = ips.is_v;
1447			tp->st_state[0] = ips.is_state[0];
1448			tp->st_state[1] = ips.is_state[1];
1449			if (forward) {
1450				tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
1451				tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
1452			} else {
1453				tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3];
1454				tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3];
1455			}
1456			tp->st_age = ips.is_die - ipsstp->iss_ticks;
1457			if ((ips.is_p == IPPROTO_TCP) ||
1458			    (ips.is_p == IPPROTO_UDP)) {
1459				tp->st_sport = ips.is_sport;
1460				tp->st_dport = ips.is_dport;
1461			}
1462		}
1463
1464		(void) ioctl(state_fd, SIOCIPFDELTOK, &token_type);
1465
1466		/* sort the array */
1467		if (tsentry != -1) {
1468			switch (sorting)
1469			{
1470			case STSORT_PR:
1471				qsort(tstable, tsentry + 1,
1472				      sizeof(statetop_t), sort_p);
1473				break;
1474			case STSORT_PKTS:
1475				qsort(tstable, tsentry + 1,
1476				      sizeof(statetop_t), sort_pkts);
1477				break;
1478			case STSORT_BYTES:
1479				qsort(tstable, tsentry + 1,
1480				      sizeof(statetop_t), sort_bytes);
1481				break;
1482			case STSORT_TTL:
1483				qsort(tstable, tsentry + 1,
1484				      sizeof(statetop_t), sort_ttl);
1485				break;
1486			case STSORT_SRCIP:
1487				qsort(tstable, tsentry + 1,
1488				      sizeof(statetop_t), sort_srcip);
1489				break;
1490			case STSORT_SRCPT:
1491				qsort(tstable, tsentry +1,
1492					sizeof(statetop_t), sort_srcpt);
1493				break;
1494			case STSORT_DSTIP:
1495				qsort(tstable, tsentry + 1,
1496				      sizeof(statetop_t), sort_dstip);
1497				break;
1498			case STSORT_DSTPT:
1499				qsort(tstable, tsentry + 1,
1500				      sizeof(statetop_t), sort_dstpt);
1501				break;
1502			default:
1503				break;
1504			}
1505		}
1506
1507		/* handle window resizes */
1508		if (handle_resize) {
1509			endwin();
1510			initscr();
1511			cbreak();
1512			noecho();
1513			curs_set(0);
1514			timeout(0);
1515			getmaxyx(stdscr, maxy, maxx);
1516			redraw = 1;
1517			handle_resize = 0;
1518                }
1519
1520		/* stop program? */
1521		if (handle_break)
1522			break;
1523
1524		/* print title */
1525		erase();
1526		attron(A_BOLD);
1527		winy = 0;
1528		move(winy,0);
1529		sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION);
1530		for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
1531			printw(" ");
1532		printw("%s", str1);
1533		attroff(A_BOLD);
1534
1535		/* just for fun add a clock */
1536		move(winy, maxx - 8);
1537		t = time(NULL);
1538		strftime(str1, 80, "%T", localtime(&t));
1539		printw("%s\n", str1);
1540
1541		/*
1542		 * print the display filters, this is placed in the loop,
1543		 * because someday I might add code for changing these
1544		 * while the programming is running :-)
1545		 */
1546		if (sport >= 0)
1547			sprintf(str1, "%s,%d", getip(ver, &saddr), sport);
1548		else
1549			sprintf(str1, "%s", getip(ver, &saddr));
1550
1551		if (dport >= 0)
1552			sprintf(str2, "%s,%d", getip(ver, &daddr), dport);
1553		else
1554			sprintf(str2, "%s", getip(ver, &daddr));
1555
1556		if (protocol < 0)
1557			strcpy(str3, "any");
1558		else if ((proto = getprotobynumber(protocol)) != NULL)
1559			sprintf(str3, "%s", proto->p_name);
1560		else
1561			sprintf(str3, "%d", protocol);
1562
1563		switch (sorting)
1564		{
1565		case STSORT_PR:
1566			sprintf(str4, "proto");
1567			break;
1568		case STSORT_PKTS:
1569			sprintf(str4, "# pkts");
1570			break;
1571		case STSORT_BYTES:
1572			sprintf(str4, "# bytes");
1573			break;
1574		case STSORT_TTL:
1575			sprintf(str4, "ttl");
1576			break;
1577		case STSORT_SRCIP:
1578			sprintf(str4, "src ip");
1579			break;
1580		case STSORT_SRCPT:
1581			sprintf(str4, "src port");
1582			break;
1583		case STSORT_DSTIP:
1584			sprintf(str4, "dest ip");
1585			break;
1586		case STSORT_DSTPT:
1587			sprintf(str4, "dest port");
1588			break;
1589		default:
1590			sprintf(str4, "unknown");
1591			break;
1592		}
1593
1594		if (reverse)
1595			strcat(str4, " (reverse)");
1596
1597		winy += 2;
1598		move(winy,0);
1599		printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
1600		       str1, str2, str3, str4);
1601
1602		/*
1603		 * For an IPv4 IP address we need at most 15 characters,
1604		 * 4 tuples of 3 digits, separated by 3 dots. Enforce this
1605		 * length, so the colums do not change positions based
1606		 * on the size of the IP address. This length makes the
1607		 * output fit in a 80 column terminal.
1608		 * We are lacking a good solution for IPv6 addresses (that
1609		 * can be longer that 15 characters), so we do not enforce
1610		 * a maximum on the IP field size.
1611		 */
1612		if (srclen < 15)
1613			srclen = 15;
1614		if (dstlen < 15)
1615			dstlen = 15;
1616
1617		/* print column description */
1618		winy += 2;
1619		move(winy,0);
1620		attron(A_BOLD);
1621		printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
1622		       srclen + 6, "Source IP", dstlen + 6, "Destination IP",
1623		       "ST", "PR", "#pkts", "#bytes", "ttl");
1624		attroff(A_BOLD);
1625
1626		/* print all the entries */
1627		tp = tstable;
1628		if (reverse)
1629			tp += tsentry;
1630
1631		if (tsentry > maxy - 6)
1632			tsentry = maxy - 6;
1633		for (i = 0; i <= tsentry; i++) {
1634			/* print src/dest and port */
1635			if ((tp->st_p == IPPROTO_TCP) ||
1636			    (tp->st_p == IPPROTO_UDP)) {
1637				sprintf(str1, "%s,%hu",
1638					getip(tp->st_v, &tp->st_src),
1639					ntohs(tp->st_sport));
1640				sprintf(str2, "%s,%hu",
1641					getip(tp->st_v, &tp->st_dst),
1642					ntohs(tp->st_dport));
1643			} else {
1644				sprintf(str1, "%s", getip(tp->st_v,
1645				    &tp->st_src));
1646				sprintf(str2, "%s", getip(tp->st_v,
1647				    &tp->st_dst));
1648			}
1649			winy++;
1650			move(winy, 0);
1651			printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
1652
1653			/* print state */
1654			sprintf(str1, "%X/%X", tp->st_state[0],
1655				tp->st_state[1]);
1656			printw(" %3s", str1);
1657
1658			/* print protocol */
1659			proto = getprotobynumber(tp->st_p);
1660			if (proto) {
1661				strncpy(str1, proto->p_name, 4);
1662				str1[4] = '\0';
1663			} else {
1664				sprintf(str1, "%d", tp->st_p);
1665			}
1666			/* just print icmp for IPv6-ICMP */
1667			if (tp->st_p == IPPROTO_ICMPV6)
1668				strcpy(str1, "icmp");
1669			printw(" %4s", str1);
1670
1671			/* print #pkt/#bytes */
1672#ifdef	USE_QUAD_T
1673			printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
1674				(unsigned long long) tp->st_bytes);
1675#else
1676			printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
1677#endif
1678			printw(" %9s", ttl_to_string(tp->st_age));
1679
1680			if (reverse)
1681				tp--;
1682			else
1683				tp++;
1684		}
1685
1686		/* screen data structure is filled, now update the screen */
1687		if (redraw)
1688			clearok(stdscr,1);
1689
1690		if (refresh() == ERR)
1691			break;
1692		if (redraw) {
1693			clearok(stdscr,0);
1694			redraw = 0;
1695		}
1696
1697		/* wait for key press or a 1 second time out period */
1698		selecttimeout.tv_sec = refreshtime;
1699		selecttimeout.tv_usec = 0;
1700		FD_ZERO(&readfd);
1701		FD_SET(0, &readfd);
1702		select(1, &readfd, NULL, NULL, &selecttimeout);
1703
1704		/* if key pressed, read all waiting keys */
1705		if (FD_ISSET(0, &readfd)) {
1706			c = wgetch(stdscr);
1707			if (c == ERR)
1708				continue;
1709
1710			if (ISALPHA(c) && ISUPPER(c))
1711				c = TOLOWER(c);
1712			if (c == 'l') {
1713				redraw = 1;
1714			} else if (c == 'q') {
1715				break;
1716			} else if (c == 'r') {
1717				reverse = !reverse;
1718			} else if (c == 'b') {
1719				forward = 0;
1720			} else if (c == 'f') {
1721				forward = 1;
1722			} else if (c == 's') {
1723				if (++sorting > STSORT_MAX)
1724					sorting = 0;
1725			}
1726		}
1727	} /* while */
1728
1729out:
1730	printw("\n");
1731	curs_set(1);
1732	/* nocbreak(); XXX - endwin() should make this redundant */
1733	endwin();
1734
1735	free(tstable);
1736	if (ret != 0)
1737		perror(errstr);
1738}
1739#endif
1740
1741
1742/*
1743 * Show fragment cache information that's held in the kernel.
1744 */
1745static void showfrstates(ifsp, ticks)
1746	ipfrstat_t *ifsp;
1747	u_long ticks;
1748{
1749	struct ipfr *ipfrtab[IPFT_SIZE], ifr;
1750	int i;
1751
1752	/*
1753	 * print out the numeric statistics
1754	 */
1755	PRINTF("IP fragment states:\n%lu\tnew\n%lu\texpired\n%lu\thits\n",
1756		ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
1757	PRINTF("%lu\tretrans\n%lu\ttoo short\n",
1758		ifsp->ifs_retrans0, ifsp->ifs_short);
1759	PRINTF("%lu\tno memory\n%lu\talready exist\n",
1760		ifsp->ifs_nomem, ifsp->ifs_exists);
1761	PRINTF("%lu\tinuse\n", ifsp->ifs_inuse);
1762	PRINTF("\n");
1763
1764	if (live_kernel == 0) {
1765		if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table,
1766			    sizeof(ipfrtab)))
1767			return;
1768	}
1769
1770	/*
1771	 * Print out the contents (if any) of the fragment cache table.
1772	 */
1773	if (live_kernel == 1) {
1774		do {
1775			if (fetchfrag(ipf_fd, IPFGENITER_FRAG, &ifr) != 0)
1776				break;
1777			if (ifr.ipfr_ifp == NULL)
1778				break;
1779			ifr.ipfr_ttl -= ticks;
1780			printfraginfo("", &ifr);
1781		} while (ifr.ipfr_next != NULL);
1782	} else {
1783		for (i = 0; i < IPFT_SIZE; i++)
1784			while (ipfrtab[i] != NULL) {
1785				if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1786					    sizeof(ifr)) == -1)
1787					break;
1788				printfraginfo("", &ifr);
1789				ipfrtab[i] = ifr.ipfr_next;
1790			}
1791	}
1792	/*
1793	 * Print out the contents (if any) of the NAT fragment cache table.
1794	 */
1795
1796	if (live_kernel == 0) {
1797		if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,
1798			    sizeof(ipfrtab)))
1799			return;
1800	}
1801
1802	if (live_kernel == 1) {
1803		do {
1804			if (fetchfrag(nat_fd, IPFGENITER_NATFRAG, &ifr) != 0)
1805				break;
1806			if (ifr.ipfr_ifp == NULL)
1807				break;
1808			ifr.ipfr_ttl -= ticks;
1809			printfraginfo("NAT: ", &ifr);
1810		} while (ifr.ipfr_next != NULL);
1811	} else {
1812		for (i = 0; i < IPFT_SIZE; i++)
1813			while (ipfrtab[i] != NULL) {
1814				if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1815					    sizeof(ifr)) == -1)
1816					break;
1817				printfraginfo("NAT: ", &ifr);
1818				ipfrtab[i] = ifr.ipfr_next;
1819			}
1820	}
1821}
1822
1823
1824/*
1825 * Show stats on how auth within IPFilter has been used
1826 */
1827static void showauthstates(asp)
1828	ipf_authstat_t *asp;
1829{
1830	frauthent_t *frap, fra;
1831	ipfgeniter_t auth;
1832	ipfobj_t obj;
1833
1834	obj.ipfo_rev = IPFILTER_VERSION;
1835	obj.ipfo_type = IPFOBJ_GENITER;
1836	obj.ipfo_size = sizeof(auth);
1837	obj.ipfo_ptr = &auth;
1838
1839	auth.igi_type = IPFGENITER_AUTH;
1840	auth.igi_nitems = 1;
1841	auth.igi_data = &fra;
1842
1843#ifdef	USE_QUAD_T
1844	printf("Authorisation hits: %"PRIu64"\tmisses %"PRIu64"\n",
1845		(unsigned long long) asp->fas_hits,
1846		(unsigned long long) asp->fas_miss);
1847#else
1848	printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
1849		asp->fas_miss);
1850#endif
1851	printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
1852		asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
1853		asp->fas_sendok);
1854	printf("queok %ld\nquefail %ld\nexpire %ld\n",
1855		asp->fas_queok, asp->fas_quefail, asp->fas_expire);
1856
1857	frap = asp->fas_faelist;
1858	while (frap) {
1859		if (live_kernel == 1) {
1860			if (ioctl(auth_fd, SIOCGENITER, &obj))
1861				break;
1862		} else {
1863			if (kmemcpy((char *)&fra, (u_long)frap,
1864				    sizeof(fra)) == -1)
1865				break;
1866		}
1867		printf("age %ld\t", fra.fae_age);
1868		printfr(&fra.fae_fr, ioctl);
1869		frap = fra.fae_next;
1870	}
1871}
1872
1873
1874/*
1875 * Display groups used for each of filter rules, accounting rules and
1876 * authentication, separately.
1877 */
1878static void showgroups(fiop)
1879	struct friostat	*fiop;
1880{
1881	static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
1882	static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH };
1883	frgroup_t *fp, grp;
1884	int on, off, i;
1885
1886	on = fiop->f_active;
1887	off = 1 - on;
1888
1889	for (i = 0; i < 3; i++) {
1890		printf("%s groups (active):\n", gnames[i]);
1891		for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL;
1892		     fp = grp.fg_next)
1893			if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1894				break;
1895			else
1896				printf("%s\n", grp.fg_name);
1897		printf("%s groups (inactive):\n", gnames[i]);
1898		for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL;
1899		     fp = grp.fg_next)
1900			if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1901				break;
1902			else
1903				printf("%s\n", grp.fg_name);
1904	}
1905}
1906
1907
1908static void parse_ipportstr(argument, ip, port)
1909	const char *argument;
1910	i6addr_t *ip;
1911	int *port;
1912{
1913	char *s, *comma;
1914	int ok = 0;
1915
1916	/* make working copy of argument, Theoretically you must be able
1917	 * to write to optarg, but that seems very ugly to me....
1918	 */
1919	s = strdup(argument);
1920	if (s == NULL)
1921		return;
1922
1923	/* get port */
1924	if ((comma = strchr(s, ',')) != NULL) {
1925		if (!strcasecmp(comma + 1, "any")) {
1926			*port = -1;
1927		} else if (!sscanf(comma + 1, "%d", port) ||
1928			   (*port < 0) || (*port > 65535)) {
1929			fprintf(stderr, "Invalid port specification in %s\n",
1930				argument);
1931			free(s);
1932			exit(-2);
1933		}
1934		*comma = '\0';
1935	}
1936
1937
1938	/* get ip address */
1939	if (!strcasecmp(s, "any")) {
1940		ip->in4.s_addr = INADDR_ANY;
1941		ok = 1;
1942#ifdef	USE_INET6
1943		ip->in6 = in6addr_any;
1944	} else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) {
1945		ok = 1;
1946#endif
1947	} else if (inet_aton(s, &ip->in4))
1948		ok = 1;
1949
1950	if (ok == 0) {
1951		fprintf(stderr, "Invalid IP address: %s\n", s);
1952		free(s);
1953		exit(-2);
1954	}
1955
1956	/* free allocated memory */
1957	free(s);
1958}
1959
1960
1961#ifdef STATETOP
1962static void sig_resize(s)
1963	int s;
1964{
1965	handle_resize = 1;
1966}
1967
1968static void sig_break(s)
1969	int s;
1970{
1971	handle_break = 1;
1972}
1973
1974static char *getip(v, addr)
1975	int v;
1976	i6addr_t *addr;
1977{
1978#ifdef  USE_INET6
1979	static char hostbuf[MAXHOSTNAMELEN+1];
1980#endif
1981
1982	if (v == 4)
1983		return inet_ntoa(addr->in4);
1984
1985#ifdef  USE_INET6
1986	(void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1);
1987	hostbuf[MAXHOSTNAMELEN] = '\0';
1988	return hostbuf;
1989#else
1990	return "IPv6";
1991#endif
1992}
1993
1994
1995static char *ttl_to_string(ttl)
1996	long int ttl;
1997{
1998	static char ttlbuf[STSTRSIZE];
1999	int hours, minutes, seconds;
2000
2001	/* ttl is in half seconds */
2002	ttl /= 2;
2003
2004	hours = ttl / 3600;
2005	ttl = ttl % 3600;
2006	minutes = ttl / 60;
2007	seconds = ttl % 60;
2008
2009	if (hours > 0)
2010		sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds);
2011	else
2012		sprintf(ttlbuf, "%2d:%02d", minutes, seconds);
2013	return ttlbuf;
2014}
2015
2016
2017static int sort_pkts(a, b)
2018	const void *a;
2019	const void *b;
2020{
2021
2022	register const statetop_t *ap = a;
2023	register const statetop_t *bp = b;
2024
2025	if (ap->st_pkts == bp->st_pkts)
2026		return 0;
2027	else if (ap->st_pkts < bp->st_pkts)
2028		return 1;
2029	return -1;
2030}
2031
2032
2033static int sort_bytes(a, b)
2034	const void *a;
2035	const void *b;
2036{
2037	register const statetop_t *ap = a;
2038	register const statetop_t *bp = b;
2039
2040	if (ap->st_bytes == bp->st_bytes)
2041		return 0;
2042	else if (ap->st_bytes < bp->st_bytes)
2043		return 1;
2044	return -1;
2045}
2046
2047
2048static int sort_p(a, b)
2049	const void *a;
2050	const void *b;
2051{
2052	register const statetop_t *ap = a;
2053	register const statetop_t *bp = b;
2054
2055	if (ap->st_p == bp->st_p)
2056		return 0;
2057	else if (ap->st_p < bp->st_p)
2058		return 1;
2059	return -1;
2060}
2061
2062
2063static int sort_ttl(a, b)
2064	const void *a;
2065	const void *b;
2066{
2067	register const statetop_t *ap = a;
2068	register const statetop_t *bp = b;
2069
2070	if (ap->st_age == bp->st_age)
2071		return 0;
2072	else if (ap->st_age < bp->st_age)
2073		return 1;
2074	return -1;
2075}
2076
2077static int sort_srcip(a, b)
2078	const void *a;
2079	const void *b;
2080{
2081	register const statetop_t *ap = a;
2082	register const statetop_t *bp = b;
2083
2084#ifdef USE_INET6
2085	if (use_inet6) {
2086		if (IP6_EQ(&ap->st_src, &bp->st_src))
2087			return 0;
2088		else if (IP6_GT(&ap->st_src, &bp->st_src))
2089			return 1;
2090	} else
2091#endif
2092	{
2093		if (ntohl(ap->st_src.in4.s_addr) ==
2094		    ntohl(bp->st_src.in4.s_addr))
2095			return 0;
2096		else if (ntohl(ap->st_src.in4.s_addr) >
2097		         ntohl(bp->st_src.in4.s_addr))
2098			return 1;
2099	}
2100	return -1;
2101}
2102
2103static int sort_srcpt(a, b)
2104	const void *a;
2105	const void *b;
2106{
2107	register const statetop_t *ap = a;
2108	register const statetop_t *bp = b;
2109
2110	if (htons(ap->st_sport) == htons(bp->st_sport))
2111		return 0;
2112	else if (htons(ap->st_sport) > htons(bp->st_sport))
2113		return 1;
2114	return -1;
2115}
2116
2117static int sort_dstip(a, b)
2118	const void *a;
2119	const void *b;
2120{
2121	register const statetop_t *ap = a;
2122	register const statetop_t *bp = b;
2123
2124#ifdef USE_INET6
2125	if (use_inet6) {
2126		if (IP6_EQ(&ap->st_dst, &bp->st_dst))
2127			return 0;
2128		else if (IP6_GT(&ap->st_dst, &bp->st_dst))
2129			return 1;
2130	} else
2131#endif
2132	{
2133		if (ntohl(ap->st_dst.in4.s_addr) ==
2134		    ntohl(bp->st_dst.in4.s_addr))
2135			return 0;
2136		else if (ntohl(ap->st_dst.in4.s_addr) >
2137		         ntohl(bp->st_dst.in4.s_addr))
2138			return 1;
2139	}
2140	return -1;
2141}
2142
2143static int sort_dstpt(a, b)
2144	const void *a;
2145	const void *b;
2146{
2147	register const statetop_t *ap = a;
2148	register const statetop_t *bp = b;
2149
2150	if (htons(ap->st_dport) == htons(bp->st_dport))
2151		return 0;
2152	else if (htons(ap->st_dport) > htons(bp->st_dport))
2153		return 1;
2154	return -1;
2155}
2156
2157#endif
2158
2159
2160ipstate_t *fetchstate(src, dst)
2161	ipstate_t *src, *dst;
2162{
2163
2164	if (live_kernel == 1) {
2165		ipfgeniter_t state;
2166		ipfobj_t obj;
2167
2168		obj.ipfo_rev = IPFILTER_VERSION;
2169		obj.ipfo_type = IPFOBJ_GENITER;
2170		obj.ipfo_size = sizeof(state);
2171		obj.ipfo_ptr = &state;
2172
2173		state.igi_type = IPFGENITER_STATE;
2174		state.igi_nitems = 1;
2175		state.igi_data = dst;
2176
2177		if (ioctl(state_fd, SIOCGENITER, &obj) != 0)
2178			return NULL;
2179		if (dst->is_next == NULL) {
2180			int n = IPFGENITER_STATE;
2181			(void) ioctl(ipf_fd,SIOCIPFDELTOK, &n);
2182		}
2183	} else {
2184		if (kmemcpy((char *)dst, (u_long)src, sizeof(*dst)))
2185			return NULL;
2186	}
2187	return dst;
2188}
2189
2190
2191static int fetchfrag(fd, type, frp)
2192	int fd, type;
2193	ipfr_t *frp;
2194{
2195	ipfgeniter_t frag;
2196	ipfobj_t obj;
2197
2198	obj.ipfo_rev = IPFILTER_VERSION;
2199	obj.ipfo_type = IPFOBJ_GENITER;
2200	obj.ipfo_size = sizeof(frag);
2201	obj.ipfo_ptr = &frag;
2202
2203	frag.igi_type = type;
2204	frag.igi_nitems = 1;
2205	frag.igi_data = frp;
2206
2207	if (ioctl(fd, SIOCGENITER, &obj))
2208		return EFAULT;
2209	return 0;
2210}
2211
2212
2213static int state_matcharray(stp, array)
2214	ipstate_t *stp;
2215	int *array;
2216{
2217	int i, n, *x, rv, p;
2218	ipfexp_t *e;
2219
2220	rv = 0;
2221
2222	for (n = array[0], x = array + 1; n > 0; x += e->ipfe_size) {
2223		e = (ipfexp_t *)x;
2224		if (e->ipfe_cmd == IPF_EXP_END)
2225			break;
2226		n -= e->ipfe_size;
2227
2228		rv = 0;
2229		/*
2230		 * The upper 16 bits currently store the protocol value.
2231		 * This is currently used with TCP and UDP port compares and
2232		 * allows "tcp.port = 80" without requiring an explicit
2233		 " "ip.pr = tcp" first.
2234		 */
2235		p = e->ipfe_cmd >> 16;
2236		if ((p != 0) && (p != stp->is_p))
2237			break;
2238
2239		switch (e->ipfe_cmd)
2240		{
2241		case IPF_EXP_IP_PR :
2242			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2243				rv |= (stp->is_p == e->ipfe_arg0[i]);
2244			}
2245			break;
2246
2247		case IPF_EXP_IP_SRCADDR :
2248			if (stp->is_v != 4)
2249				break;
2250			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2251				rv |= ((stp->is_saddr &
2252					e->ipfe_arg0[i * 2 + 1]) ==
2253				       e->ipfe_arg0[i * 2]);
2254			}
2255			break;
2256
2257		case IPF_EXP_IP_DSTADDR :
2258			if (stp->is_v != 4)
2259				break;
2260			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2261				rv |= ((stp->is_daddr &
2262					e->ipfe_arg0[i * 2 + 1]) ==
2263				       e->ipfe_arg0[i * 2]);
2264			}
2265			break;
2266
2267		case IPF_EXP_IP_ADDR :
2268			if (stp->is_v != 4)
2269				break;
2270			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2271				rv |= ((stp->is_saddr &
2272					e->ipfe_arg0[i * 2 + 1]) ==
2273				       e->ipfe_arg0[i * 2]) ||
2274				      ((stp->is_daddr &
2275					e->ipfe_arg0[i * 2 + 1]) ==
2276				       e->ipfe_arg0[i * 2]);
2277			}
2278			break;
2279
2280#ifdef USE_INET6
2281		case IPF_EXP_IP6_SRCADDR :
2282			if (stp->is_v != 6)
2283				break;
2284			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2285				rv |= IP6_MASKEQ(&stp->is_src,
2286						 &e->ipfe_arg0[i * 8 + 4],
2287						 &e->ipfe_arg0[i * 8]);
2288			}
2289			break;
2290
2291		case IPF_EXP_IP6_DSTADDR :
2292			if (stp->is_v != 6)
2293				break;
2294			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2295				rv |= IP6_MASKEQ(&stp->is_dst,
2296						 &e->ipfe_arg0[i * 8 + 4],
2297						 &e->ipfe_arg0[i * 8]);
2298			}
2299			break;
2300
2301		case IPF_EXP_IP6_ADDR :
2302			if (stp->is_v != 6)
2303				break;
2304			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2305				rv |= IP6_MASKEQ(&stp->is_src,
2306						 &e->ipfe_arg0[i * 8 + 4],
2307						 &e->ipfe_arg0[i * 8]) ||
2308				      IP6_MASKEQ(&stp->is_dst,
2309						 &e->ipfe_arg0[i * 8 + 4],
2310						 &e->ipfe_arg0[i * 8]);
2311			}
2312			break;
2313#endif
2314
2315		case IPF_EXP_UDP_PORT :
2316		case IPF_EXP_TCP_PORT :
2317			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2318				rv |= (stp->is_sport == e->ipfe_arg0[i]) ||
2319				      (stp->is_dport == e->ipfe_arg0[i]);
2320			}
2321			break;
2322
2323		case IPF_EXP_UDP_SPORT :
2324		case IPF_EXP_TCP_SPORT :
2325			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2326				rv |= (stp->is_sport == e->ipfe_arg0[i]);
2327			}
2328			break;
2329
2330		case IPF_EXP_UDP_DPORT :
2331		case IPF_EXP_TCP_DPORT :
2332			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2333				rv |= (stp->is_dport == e->ipfe_arg0[i]);
2334			}
2335			break;
2336
2337		case IPF_EXP_IDLE_GT :
2338			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2339				rv |= (stp->is_die < e->ipfe_arg0[i]);
2340			}
2341			break;
2342
2343		case IPF_EXP_TCP_STATE :
2344			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2345				rv |= (stp->is_state[0] == e->ipfe_arg0[i]) ||
2346				      (stp->is_state[1] == e->ipfe_arg0[i]);
2347			}
2348			break;
2349		}
2350		rv ^= e->ipfe_not;
2351
2352		if (rv == 0)
2353			break;
2354	}
2355
2356	return rv;
2357}
2358
2359
2360static void showtqtable_live(fd)
2361	int fd;
2362{
2363	ipftq_t table[IPF_TCP_NSTATES];
2364	ipfobj_t obj;
2365
2366	bzero((char *)&obj, sizeof(obj));
2367	obj.ipfo_rev = IPFILTER_VERSION;
2368	obj.ipfo_size = sizeof(table);
2369	obj.ipfo_ptr = (void *)table;
2370	obj.ipfo_type = IPFOBJ_STATETQTAB;
2371
2372	if (ioctl(fd, SIOCGTQTAB, &obj) == 0) {
2373		printtqtable(table);
2374	}
2375}
2376