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