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