1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3145510Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5145510Sdarrenr *
6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145510Sdarrenr */
8145510Sdarrenr#ifdef __FreeBSD__
9145510Sdarrenr# ifndef __FreeBSD_cc_version
10145510Sdarrenr#  include <osreldate.h>
11145510Sdarrenr# else
12145510Sdarrenr#  if __FreeBSD_cc_version < 430000
13145510Sdarrenr#   include <osreldate.h>
14145510Sdarrenr#  endif
15145510Sdarrenr# endif
16145510Sdarrenr#endif
17145510Sdarrenr#include <sys/ioctl.h>
18255332Scy#include <ctype.h>
19145510Sdarrenr#include <fcntl.h>
20145510Sdarrenr#ifdef linux
21145510Sdarrenr# include <linux/a.out.h>
22145510Sdarrenr#else
23145510Sdarrenr# include <nlist.h>
24145510Sdarrenr#endif
25145510Sdarrenr#include <ctype.h>
26145510Sdarrenr#if defined(sun) && (defined(__svr4__) || defined(__SVR4))
27145510Sdarrenr# include <stddef.h>
28145510Sdarrenr#endif
29145510Sdarrenr#include "ipf.h"
30145510Sdarrenr#include "netinet/ipl.h"
31145510Sdarrenr#if defined(STATETOP)
32145510Sdarrenr# if defined(_BSDI_VERSION)
33145510Sdarrenr#  undef STATETOP
34145510Sdarrenr# endif
35145510Sdarrenr# if defined(__FreeBSD__) && \
36145510Sdarrenr     (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000))
37145510Sdarrenr#  undef STATETOP
38145510Sdarrenr# endif
39145510Sdarrenr# if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105000000)
40145510Sdarrenr#  undef STATETOP
41145510Sdarrenr# endif
42145510Sdarrenr# if defined(sun)
43145510Sdarrenr#  if defined(__svr4__) || defined(__SVR4)
44145510Sdarrenr#   include <sys/select.h>
45145510Sdarrenr#  else
46145510Sdarrenr#   undef STATETOP	/* NOT supported on SunOS4 */
47145510Sdarrenr#  endif
48145510Sdarrenr# endif
49145510Sdarrenr#endif
50145510Sdarrenr#if defined(STATETOP) && !defined(linux)
51145510Sdarrenr# include <netinet/ip_var.h>
52145510Sdarrenr# include <netinet/tcp_fsm.h>
53145510Sdarrenr#endif
54145510Sdarrenr#ifdef STATETOP
55145510Sdarrenr# include <ctype.h>
56145510Sdarrenr# include <signal.h>
57170268Sdarrenr# include <time.h>
58145510Sdarrenr# if SOLARIS || defined(__NetBSD__) || defined(_BSDI_VERSION) || \
59145510Sdarrenr     defined(__sgi)
60145510Sdarrenr#  ifdef ERR
61145510Sdarrenr#   undef ERR
62145510Sdarrenr#  endif
63145510Sdarrenr#  include <curses.h>
64145510Sdarrenr# else /* SOLARIS */
65145510Sdarrenr#  include <ncurses.h>
66145510Sdarrenr# endif /* SOLARIS */
67145510Sdarrenr#endif /* STATETOP */
68145510Sdarrenr#include "kmem.h"
69145510Sdarrenr#if defined(__NetBSD__) || (__OpenBSD__)
70145510Sdarrenr# include <paths.h>
71145510Sdarrenr#endif
72145510Sdarrenr
73145510Sdarrenr#if !defined(lint)
74145510Sdarrenrstatic const char sccsid[] = "@(#)fils.c	1.21 4/20/96 (C) 1993-2000 Darren Reed";
75255332Scystatic const char rcsid[] = "@(#)$Id$";
76145510Sdarrenr#endif
77145510Sdarrenr
78145510Sdarrenr#ifdef __hpux
79145510Sdarrenr# define	nlist	nlist64
80145510Sdarrenr#endif
81145510Sdarrenr
82145510Sdarrenrextern	char	*optarg;
83145510Sdarrenrextern	int	optind;
84145510Sdarrenrextern	int	opterr;
85145510Sdarrenr
86145510Sdarrenr#define	PRINTF	(void)printf
87145510Sdarrenr#define	FPRINTF	(void)fprintf
88145510Sdarrenrstatic	char	*filters[4] = { "ipfilter(in)", "ipfilter(out)",
89145510Sdarrenr				"ipacct(in)", "ipacct(out)" };
90145510Sdarrenrstatic	int	state_logging = -1;
91255332Scystatic	wordtab_t	*state_fields = NULL;
92145510Sdarrenr
93255332Scyint	nohdrfields = 0;
94145510Sdarrenrint	opts = 0;
95145510Sdarrenrint	use_inet6 = 0;
96145510Sdarrenrint	live_kernel = 1;
97145510Sdarrenrint	state_fd = -1;
98145510Sdarrenrint	ipf_fd = -1;
99170268Sdarrenrint	auth_fd = -1;
100170268Sdarrenrint	nat_fd = -1;
101170268Sdarrenrfrgroup_t *grtop = NULL;
102170268Sdarrenrfrgroup_t *grtail = NULL;
103145510Sdarrenr
104255332Scychar *blockreasons[FRB_MAX_VALUE + 1] = {
105255332Scy	"packet blocked",
106255332Scy	"log rule failure",
107255332Scy	"pps rate exceeded",
108255332Scy	"jumbogram",
109255332Scy	"makefrip failed",
110255332Scy	"cannot add state",
111255332Scy	"IP ID update failed",
112255332Scy	"log-or-block failed",
113255332Scy	"decapsulate failure",
114255332Scy	"cannot create new auth entry",
115255332Scy	"packet queued for auth",
116255332Scy	"buffer coalesce failure",
117255332Scy	"buffer pullup failure",
118255332Scy	"auth feedback",
119255332Scy	"bad fragment",
120255332Scy	"IPv4 NAT failure",
121255332Scy	"IPv6 NAT failure"
122255332Scy};
123255332Scy
124145510Sdarrenr#ifdef STATETOP
125145510Sdarrenr#define	STSTRSIZE 	80
126145510Sdarrenr#define	STGROWSIZE	16
127145510Sdarrenr#define	HOSTNMLEN	40
128145510Sdarrenr
129145510Sdarrenr#define	STSORT_PR	0
130145510Sdarrenr#define	STSORT_PKTS	1
131145510Sdarrenr#define	STSORT_BYTES	2
132145510Sdarrenr#define	STSORT_TTL	3
133145510Sdarrenr#define	STSORT_SRCIP	4
134145510Sdarrenr#define	STSORT_SRCPT	5
135145510Sdarrenr#define	STSORT_DSTIP	6
136145510Sdarrenr#define	STSORT_DSTPT	7
137145510Sdarrenr#define	STSORT_MAX	STSORT_DSTPT
138145510Sdarrenr#define	STSORT_DEFAULT	STSORT_BYTES
139145510Sdarrenr
140145510Sdarrenr
141145510Sdarrenrtypedef struct statetop {
142145510Sdarrenr	i6addr_t	st_src;
143145510Sdarrenr	i6addr_t	st_dst;
144145510Sdarrenr	u_short		st_sport;
145145510Sdarrenr	u_short 	st_dport;
146145510Sdarrenr	u_char		st_p;
147145510Sdarrenr	u_char		st_v;
148145510Sdarrenr	u_char		st_state[2];
149145510Sdarrenr	U_QUAD_T	st_pkts;
150145510Sdarrenr	U_QUAD_T	st_bytes;
151145510Sdarrenr	u_long		st_age;
152145510Sdarrenr} statetop_t;
153145510Sdarrenr#endif
154145510Sdarrenr
155145510Sdarrenrint		main __P((int, char *[]));
156145510Sdarrenr
157170268Sdarrenrstatic	int	fetchfrag __P((int, int, ipfr_t *));
158145510Sdarrenrstatic	void	showstats __P((friostat_t *, u_32_t));
159170268Sdarrenrstatic	void	showfrstates __P((ipfrstat_t *, u_long));
160145510Sdarrenrstatic	void	showlist __P((friostat_t *));
161255332Scystatic	void	showstatestats __P((ips_stat_t *));
162255332Scystatic	void	showipstates __P((ips_stat_t *, int *));
163255332Scystatic	void	showauthstates __P((ipf_authstat_t *));
164255332Scystatic	void	showtqtable_live __P((int));
165145510Sdarrenrstatic	void	showgroups __P((friostat_t *));
166145510Sdarrenrstatic	void	usage __P((char *));
167255332Scystatic	int	state_matcharray __P((ipstate_t *, int *));
168255332Scystatic	int	printlivelist __P((friostat_t *, int, int, frentry_t *,
169255332Scy				   char *, char *));
170255332Scystatic	void	printdeadlist __P((friostat_t *, int, int, frentry_t *,
171255332Scy				   char *, char *));
172255332Scystatic	void	printside __P((char *, ipf_statistics_t *));
173145510Sdarrenrstatic	void	parse_ipportstr __P((const char *, i6addr_t *, int *));
174145510Sdarrenrstatic	void	ipfstate_live __P((char *, friostat_t **, ips_stat_t **,
175255332Scy				   ipfrstat_t **, ipf_authstat_t **, u_32_t *));
176145510Sdarrenrstatic	void	ipfstate_dead __P((char *, friostat_t **, ips_stat_t **,
177255332Scy				   ipfrstat_t **, ipf_authstat_t **, u_32_t *));
178170268Sdarrenrstatic	ipstate_t *fetchstate __P((ipstate_t *, ipstate_t *));
179145510Sdarrenr#ifdef STATETOP
180145510Sdarrenrstatic	void	topipstates __P((i6addr_t, i6addr_t, int, int, int,
181255332Scy				 int, int, int, int *));
182145510Sdarrenrstatic	void	sig_break __P((int));
183145510Sdarrenrstatic	void	sig_resize __P((int));
184145510Sdarrenrstatic	char	*getip __P((int, i6addr_t *));
185145510Sdarrenrstatic	char	*ttl_to_string __P((long));
186145510Sdarrenrstatic	int	sort_p __P((const void *, const void *));
187145510Sdarrenrstatic	int	sort_pkts __P((const void *, const void *));
188145510Sdarrenrstatic	int	sort_bytes __P((const void *, const void *));
189145510Sdarrenrstatic	int	sort_ttl __P((const void *, const void *));
190145510Sdarrenrstatic	int	sort_srcip __P((const void *, const void *));
191145510Sdarrenrstatic	int	sort_srcpt __P((const void *, const void *));
192145510Sdarrenrstatic	int	sort_dstip __P((const void *, const void *));
193145510Sdarrenrstatic	int	sort_dstpt __P((const void *, const void *));
194145510Sdarrenr#endif
195145510Sdarrenr
196145510Sdarrenr
197145510Sdarrenrstatic void usage(name)
198255332Scy	char *name;
199145510Sdarrenr{
200145510Sdarrenr#ifdef  USE_INET6
201145510Sdarrenr	fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name);
202145510Sdarrenr#else
203145510Sdarrenr	fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name);
204145510Sdarrenr#endif
205145510Sdarrenr	fprintf(stderr, "       %s [-M corefile] [-N symbol-list]\n", name);
206145510Sdarrenr#ifdef	USE_INET6
207145510Sdarrenr	fprintf(stderr, "       %s -t [-6C] ", name);
208145510Sdarrenr#else
209145510Sdarrenr	fprintf(stderr, "       %s -t [-C] ", name);
210145510Sdarrenr#endif
211145510Sdarrenr	fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n");
212145510Sdarrenr	exit(1);
213145510Sdarrenr}
214145510Sdarrenr
215145510Sdarrenr
216145510Sdarrenrint main(argc,argv)
217255332Scy	int argc;
218255332Scy	char *argv[];
219145510Sdarrenr{
220255332Scy	ipf_authstat_t	frauthst;
221255332Scy	ipf_authstat_t	*frauthstp = &frauthst;
222145510Sdarrenr	friostat_t fio;
223145510Sdarrenr	friostat_t *fiop = &fio;
224145510Sdarrenr	ips_stat_t ipsst;
225145510Sdarrenr	ips_stat_t *ipsstp = &ipsst;
226145510Sdarrenr	ipfrstat_t ifrst;
227145510Sdarrenr	ipfrstat_t *ifrstp = &ifrst;
228255332Scy	char *options;
229255332Scy	char *kern = NULL;
230255332Scy	char *memf = NULL;
231255332Scy	int c;
232255332Scy	int myoptind;
233255332Scy	int *filter = NULL;
234145510Sdarrenr
235145510Sdarrenr	int protocol = -1;		/* -1 = wild card for any protocol */
236145510Sdarrenr	int refreshtime = 1; 		/* default update time */
237145510Sdarrenr	int sport = -1;			/* -1 = wild card for any source port */
238145510Sdarrenr	int dport = -1;			/* -1 = wild card for any dest port */
239145510Sdarrenr	int topclosed = 0;		/* do not show closed tcp sessions */
240145510Sdarrenr	i6addr_t saddr, daddr;
241145510Sdarrenr	u_32_t frf;
242145510Sdarrenr
243145510Sdarrenr#ifdef	USE_INET6
244255332Scy	options = "6aACdfghIilnostvD:m:M:N:O:P:RS:T:";
245145510Sdarrenr#else
246255332Scy	options = "aACdfghIilnostvD:m:M:N:O:P:RS:T:";
247145510Sdarrenr#endif
248145510Sdarrenr
249145510Sdarrenr	saddr.in4.s_addr = INADDR_ANY; 	/* default any v4 source addr */
250145510Sdarrenr	daddr.in4.s_addr = INADDR_ANY; 	/* default any v4 dest addr */
251145510Sdarrenr#ifdef	USE_INET6
252145510Sdarrenr	saddr.in6 = in6addr_any;	/* default any v6 source addr */
253145510Sdarrenr	daddr.in6 = in6addr_any;	/* default any v6 dest addr */
254145510Sdarrenr#endif
255145510Sdarrenr
256145510Sdarrenr	/* Don't warn about invalid flags when we run getopt for the 1st time */
257145510Sdarrenr	opterr = 0;
258145510Sdarrenr
259145510Sdarrenr	/*
260145510Sdarrenr	 * Parse these two arguments now lest there be any buffer overflows
261145510Sdarrenr	 * in the parsing of the rest.
262145510Sdarrenr	 */
263145510Sdarrenr	myoptind = optind;
264145510Sdarrenr	while ((c = getopt(argc, argv, options)) != -1) {
265145510Sdarrenr		switch (c)
266145510Sdarrenr		{
267145510Sdarrenr		case 'M' :
268145510Sdarrenr			memf = optarg;
269145510Sdarrenr			live_kernel = 0;
270145510Sdarrenr			break;
271145510Sdarrenr		case 'N' :
272145510Sdarrenr			kern = optarg;
273145510Sdarrenr			live_kernel = 0;
274145510Sdarrenr			break;
275145510Sdarrenr		}
276145510Sdarrenr	}
277145510Sdarrenr	optind = myoptind;
278145510Sdarrenr
279145510Sdarrenr	if (live_kernel == 1) {
280145510Sdarrenr		if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) {
281145510Sdarrenr			perror("open(IPSTATE_NAME)");
282145510Sdarrenr			exit(-1);
283145510Sdarrenr		}
284170268Sdarrenr		if ((auth_fd = open(IPAUTH_NAME, O_RDONLY)) == -1) {
285170268Sdarrenr			perror("open(IPAUTH_NAME)");
286170268Sdarrenr			exit(-1);
287170268Sdarrenr		}
288170268Sdarrenr		if ((nat_fd = open(IPNAT_NAME, O_RDONLY)) == -1) {
289170268Sdarrenr			perror("open(IPAUTH_NAME)");
290170268Sdarrenr			exit(-1);
291170268Sdarrenr		}
292170268Sdarrenr		if ((ipf_fd = open(IPL_NAME, O_RDONLY)) == -1) {
293170268Sdarrenr			fprintf(stderr, "open(%s)", IPL_NAME);
294145510Sdarrenr			perror("");
295145510Sdarrenr			exit(-1);
296145510Sdarrenr		}
297145510Sdarrenr	}
298145510Sdarrenr
299145510Sdarrenr	if (kern != NULL || memf != NULL) {
300145510Sdarrenr		(void)setgid(getgid());
301145510Sdarrenr		(void)setuid(getuid());
302145510Sdarrenr	}
303145510Sdarrenr
304170268Sdarrenr	if (live_kernel == 1) {
305170268Sdarrenr		(void) checkrev(IPL_NAME);
306170268Sdarrenr	} else {
307170268Sdarrenr		if (openkmem(kern, memf) == -1)
308170268Sdarrenr			exit(-1);
309170268Sdarrenr	}
310145510Sdarrenr
311145510Sdarrenr	(void)setgid(getgid());
312145510Sdarrenr	(void)setuid(getuid());
313145510Sdarrenr
314145510Sdarrenr	opterr = 1;
315145510Sdarrenr
316145510Sdarrenr	while ((c = getopt(argc, argv, options)) != -1)
317145510Sdarrenr	{
318145510Sdarrenr		switch (c)
319145510Sdarrenr		{
320145510Sdarrenr#ifdef	USE_INET6
321145510Sdarrenr		case '6' :
322145510Sdarrenr			use_inet6 = 1;
323145510Sdarrenr			break;
324145510Sdarrenr#endif
325145510Sdarrenr		case 'a' :
326145510Sdarrenr			opts |= OPT_ACCNT|OPT_SHOWLIST;
327145510Sdarrenr			break;
328145510Sdarrenr		case 'A' :
329145510Sdarrenr			opts |= OPT_AUTHSTATS;
330145510Sdarrenr			break;
331145510Sdarrenr		case 'C' :
332145510Sdarrenr			topclosed = 1;
333145510Sdarrenr			break;
334145510Sdarrenr		case 'd' :
335145510Sdarrenr			opts |= OPT_DEBUG;
336145510Sdarrenr			break;
337145510Sdarrenr		case 'D' :
338145510Sdarrenr			parse_ipportstr(optarg, &daddr, &dport);
339145510Sdarrenr			break;
340145510Sdarrenr		case 'f' :
341145510Sdarrenr			opts |= OPT_FRSTATES;
342145510Sdarrenr			break;
343145510Sdarrenr		case 'g' :
344145510Sdarrenr			opts |= OPT_GROUPS;
345145510Sdarrenr			break;
346145510Sdarrenr		case 'h' :
347145510Sdarrenr			opts |= OPT_HITS;
348145510Sdarrenr			break;
349145510Sdarrenr		case 'i' :
350145510Sdarrenr			opts |= OPT_INQUE|OPT_SHOWLIST;
351145510Sdarrenr			break;
352145510Sdarrenr		case 'I' :
353145510Sdarrenr			opts |= OPT_INACTIVE;
354145510Sdarrenr			break;
355145510Sdarrenr		case 'l' :
356145510Sdarrenr			opts |= OPT_SHOWLIST;
357145510Sdarrenr			break;
358255332Scy		case 'm' :
359255332Scy			filter = parseipfexpr(optarg, NULL);
360255332Scy			if (filter == NULL) {
361255332Scy				fprintf(stderr, "Error parseing '%s'\n",
362255332Scy					optarg);
363255332Scy				exit(1);
364255332Scy			}
365255332Scy			break;
366145510Sdarrenr		case 'M' :
367145510Sdarrenr			break;
368145510Sdarrenr		case 'N' :
369145510Sdarrenr			break;
370145510Sdarrenr		case 'n' :
371145510Sdarrenr			opts |= OPT_SHOWLINENO;
372145510Sdarrenr			break;
373145510Sdarrenr		case 'o' :
374145510Sdarrenr			opts |= OPT_OUTQUE|OPT_SHOWLIST;
375145510Sdarrenr			break;
376255332Scy		case 'O' :
377255332Scy			state_fields = parsefields(statefields, optarg);
378255332Scy			break;
379145510Sdarrenr		case 'P' :
380145510Sdarrenr			protocol = getproto(optarg);
381145510Sdarrenr			if (protocol == -1) {
382145510Sdarrenr				fprintf(stderr, "%s: Invalid protocol: %s\n",
383145510Sdarrenr					argv[0], optarg);
384145510Sdarrenr				exit(-2);
385145510Sdarrenr			}
386145510Sdarrenr			break;
387145510Sdarrenr		case 'R' :
388145510Sdarrenr			opts |= OPT_NORESOLVE;
389145510Sdarrenr			break;
390145510Sdarrenr		case 's' :
391145510Sdarrenr			opts |= OPT_IPSTATES;
392145510Sdarrenr			break;
393145510Sdarrenr		case 'S' :
394145510Sdarrenr			parse_ipportstr(optarg, &saddr, &sport);
395145510Sdarrenr			break;
396145510Sdarrenr		case 't' :
397145510Sdarrenr#ifdef STATETOP
398145510Sdarrenr			opts |= OPT_STATETOP;
399145510Sdarrenr			break;
400145510Sdarrenr#else
401145510Sdarrenr			fprintf(stderr,
402145510Sdarrenr				"%s: state top facility not compiled in\n",
403145510Sdarrenr				argv[0]);
404145510Sdarrenr			exit(-2);
405145510Sdarrenr#endif
406145510Sdarrenr		case 'T' :
407145510Sdarrenr			if (!sscanf(optarg, "%d", &refreshtime) ||
408145510Sdarrenr				    (refreshtime <= 0)) {
409145510Sdarrenr				fprintf(stderr,
410145510Sdarrenr					"%s: Invalid refreshtime < 1 : %s\n",
411145510Sdarrenr					argv[0], optarg);
412145510Sdarrenr				exit(-2);
413145510Sdarrenr			}
414145510Sdarrenr			break;
415145510Sdarrenr		case 'v' :
416145510Sdarrenr			opts |= OPT_VERBOSE;
417145510Sdarrenr			break;
418145510Sdarrenr		default :
419145510Sdarrenr			usage(argv[0]);
420145510Sdarrenr			break;
421145510Sdarrenr		}
422145510Sdarrenr	}
423145510Sdarrenr
424145510Sdarrenr	if (live_kernel == 1) {
425145510Sdarrenr		bzero((char *)&fio, sizeof(fio));
426145510Sdarrenr		bzero((char *)&ipsst, sizeof(ipsst));
427145510Sdarrenr		bzero((char *)&ifrst, sizeof(ifrst));
428145510Sdarrenr
429170268Sdarrenr		ipfstate_live(IPL_NAME, &fiop, &ipsstp, &ifrstp,
430145510Sdarrenr			      &frauthstp, &frf);
431255332Scy	} else {
432145510Sdarrenr		ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf);
433255332Scy	}
434145510Sdarrenr
435145510Sdarrenr	if (opts & OPT_IPSTATES) {
436255332Scy		showipstates(ipsstp, filter);
437145510Sdarrenr	} else if (opts & OPT_SHOWLIST) {
438145510Sdarrenr		showlist(fiop);
439145510Sdarrenr		if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){
440145510Sdarrenr			opts &= ~OPT_OUTQUE;
441145510Sdarrenr			showlist(fiop);
442145510Sdarrenr		}
443145510Sdarrenr	} else if (opts & OPT_FRSTATES)
444170268Sdarrenr		showfrstates(ifrstp, fiop->f_ticks);
445145510Sdarrenr#ifdef STATETOP
446145510Sdarrenr	else if (opts & OPT_STATETOP)
447145510Sdarrenr		topipstates(saddr, daddr, sport, dport, protocol,
448255332Scy			    use_inet6 ? 6 : 4, refreshtime, topclosed, filter);
449145510Sdarrenr#endif
450145510Sdarrenr	else if (opts & OPT_AUTHSTATS)
451145510Sdarrenr		showauthstates(frauthstp);
452145510Sdarrenr	else if (opts & OPT_GROUPS)
453145510Sdarrenr		showgroups(fiop);
454145510Sdarrenr	else
455145510Sdarrenr		showstats(fiop, frf);
456145510Sdarrenr
457145510Sdarrenr	return 0;
458145510Sdarrenr}
459145510Sdarrenr
460145510Sdarrenr
461145510Sdarrenr/*
462145510Sdarrenr * Fill in the stats structures from the live kernel, using a combination
463145510Sdarrenr * of ioctl's and copying directly from kernel memory.
464145510Sdarrenr */
465145510Sdarrenrstatic void ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
466255332Scy	char *device;
467255332Scy	friostat_t **fiopp;
468255332Scy	ips_stat_t **ipsstpp;
469255332Scy	ipfrstat_t **ifrstpp;
470255332Scy	ipf_authstat_t **frauthstpp;
471255332Scy	u_32_t *frfp;
472145510Sdarrenr{
473145510Sdarrenr	ipfobj_t ipfo;
474145510Sdarrenr
475145510Sdarrenr	if (checkrev(device) == -1) {
476145510Sdarrenr		fprintf(stderr, "User/kernel version check failed\n");
477145510Sdarrenr		exit(1);
478145510Sdarrenr	}
479145510Sdarrenr
480145510Sdarrenr	if ((opts & OPT_AUTHSTATS) == 0) {
481145510Sdarrenr		bzero((caddr_t)&ipfo, sizeof(ipfo));
482145510Sdarrenr		ipfo.ipfo_rev = IPFILTER_VERSION;
483170268Sdarrenr		ipfo.ipfo_type = IPFOBJ_IPFSTAT;
484145510Sdarrenr		ipfo.ipfo_size = sizeof(friostat_t);
485145510Sdarrenr		ipfo.ipfo_ptr = (void *)*fiopp;
486145510Sdarrenr
487145510Sdarrenr		if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) {
488255332Scy			ipferror(ipf_fd, "ioctl(ipf:SIOCGETFS)");
489145510Sdarrenr			exit(-1);
490145510Sdarrenr		}
491145510Sdarrenr
492145510Sdarrenr		if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1)
493255332Scy			ipferror(ipf_fd, "ioctl(SIOCGETFF)");
494145510Sdarrenr	}
495145510Sdarrenr
496145510Sdarrenr	if ((opts & OPT_IPSTATES) != 0) {
497145510Sdarrenr
498145510Sdarrenr		bzero((caddr_t)&ipfo, sizeof(ipfo));
499145510Sdarrenr		ipfo.ipfo_rev = IPFILTER_VERSION;
500170268Sdarrenr		ipfo.ipfo_type = IPFOBJ_STATESTAT;
501145510Sdarrenr		ipfo.ipfo_size = sizeof(ips_stat_t);
502145510Sdarrenr		ipfo.ipfo_ptr = (void *)*ipsstpp;
503145510Sdarrenr
504145510Sdarrenr		if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
505255332Scy			ipferror(state_fd, "ioctl(state:SIOCGETFS)");
506145510Sdarrenr			exit(-1);
507145510Sdarrenr		}
508145510Sdarrenr		if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) {
509255332Scy			ipferror(state_fd, "ioctl(state:SIOCGETLG)");
510145510Sdarrenr			exit(-1);
511145510Sdarrenr		}
512145510Sdarrenr	}
513145510Sdarrenr
514145510Sdarrenr	if ((opts & OPT_FRSTATES) != 0) {
515145510Sdarrenr		bzero((caddr_t)&ipfo, sizeof(ipfo));
516145510Sdarrenr		ipfo.ipfo_rev = IPFILTER_VERSION;
517170268Sdarrenr		ipfo.ipfo_type = IPFOBJ_FRAGSTAT;
518145510Sdarrenr		ipfo.ipfo_size = sizeof(ipfrstat_t);
519145510Sdarrenr		ipfo.ipfo_ptr = (void *)*ifrstpp;
520255332Scy
521145510Sdarrenr		if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) {
522255332Scy			ipferror(ipf_fd, "ioctl(SIOCGFRST)");
523145510Sdarrenr			exit(-1);
524145510Sdarrenr		}
525145510Sdarrenr	}
526145510Sdarrenr
527170268Sdarrenr	if (opts & OPT_DEBUG)
528145510Sdarrenr		PRINTF("opts %#x name %s\n", opts, device);
529145510Sdarrenr
530145510Sdarrenr	if ((opts & OPT_AUTHSTATS) != 0) {
531145510Sdarrenr		bzero((caddr_t)&ipfo, sizeof(ipfo));
532145510Sdarrenr		ipfo.ipfo_rev = IPFILTER_VERSION;
533170268Sdarrenr		ipfo.ipfo_type = IPFOBJ_AUTHSTAT;
534255332Scy		ipfo.ipfo_size = sizeof(ipf_authstat_t);
535145510Sdarrenr		ipfo.ipfo_ptr = (void *)*frauthstpp;
536145510Sdarrenr
537170268Sdarrenr	    	if (ioctl(auth_fd, SIOCATHST, &ipfo) == -1) {
538255332Scy			ipferror(auth_fd, "ioctl(SIOCATHST)");
539145510Sdarrenr			exit(-1);
540145510Sdarrenr		}
541145510Sdarrenr	}
542145510Sdarrenr}
543145510Sdarrenr
544145510Sdarrenr
545145510Sdarrenr/*
546145510Sdarrenr * Build up the stats structures from data held in the "core" memory.
547145510Sdarrenr * This is mainly useful when looking at data in crash dumps and ioctl's
548145510Sdarrenr * just won't work any more.
549145510Sdarrenr */
550145510Sdarrenrstatic void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
551255332Scy	char *kernel;
552255332Scy	friostat_t **fiopp;
553255332Scy	ips_stat_t **ipsstpp;
554255332Scy	ipfrstat_t **ifrstpp;
555255332Scy	ipf_authstat_t **frauthstpp;
556255332Scy	u_32_t *frfp;
557145510Sdarrenr{
558255332Scy	static ipf_authstat_t frauthst, *frauthstp;
559255332Scy	static ipftq_t ipstcptab[IPF_TCP_NSTATES];
560145510Sdarrenr	static ips_stat_t ipsst, *ipsstp;
561145510Sdarrenr	static ipfrstat_t ifrst, *ifrstp;
562145510Sdarrenr	static friostat_t fio, *fiop;
563145510Sdarrenr	int temp;
564145510Sdarrenr
565145510Sdarrenr	void *rules[2][2];
566170268Sdarrenr	struct nlist deadlist[44] = {
567255332Scy		{ "ipf_auth_stats",	0, 0, 0, 0 },		/* 0 */
568255332Scy		{ "fae_list",		0, 0, 0, 0 },
569255332Scy		{ "ipauth",		0, 0, 0, 0 },
570255332Scy		{ "ipf_auth_list",		0, 0, 0, 0 },
571255332Scy		{ "ipf_auth_start",		0, 0, 0, 0 },
572255332Scy		{ "ipf_auth_end",		0, 0, 0, 0 },		/* 5 */
573255332Scy		{ "ipf_auth_next",		0, 0, 0, 0 },
574255332Scy		{ "ipf_auth",		0, 0, 0, 0 },
575255332Scy		{ "ipf_auth_used",		0, 0, 0, 0 },
576255332Scy		{ "ipf_auth_size",		0, 0, 0, 0 },
577255332Scy		{ "ipf_auth_defaultage",		0, 0, 0, 0 },	/* 10 */
578255332Scy		{ "ipf_auth_pkts",		0, 0, 0, 0 },
579255332Scy		{ "ipf_auth_lock",		0, 0, 0, 0 },
580255332Scy		{ "frstats",		0, 0, 0, 0 },
581255332Scy		{ "ips_stats",		0, 0, 0, 0 },
582255332Scy		{ "ips_num",		0, 0, 0, 0 },			/* 15 */
583255332Scy		{ "ips_wild",		0, 0, 0, 0 },
584255332Scy		{ "ips_list",		0, 0, 0, 0 },
585255332Scy		{ "ips_table",		0, 0, 0, 0 },
586255332Scy		{ "ipf_state_max",		0, 0, 0, 0 },
587255332Scy		{ "ipf_state_size",		0, 0, 0, 0 },		/* 20 */
588255332Scy		{ "ipf_state_doflush",		0, 0, 0, 0 },
589255332Scy		{ "ipf_state_lock",		0, 0, 0, 0 },
590255332Scy		{ "ipfr_heads",		0, 0, 0, 0 },
591255332Scy		{ "ipfr_nattab",		0, 0, 0, 0 },
592255332Scy		{ "ipfr_stats",		0, 0, 0, 0 },		/* 25 */
593255332Scy		{ "ipfr_inuse",		0, 0, 0, 0 },
594255332Scy		{ "ipf_ipfrttl",		0, 0, 0, 0 },
595255332Scy		{ "ipf_frag_lock",		0, 0, 0, 0 },
596255332Scy		{ "ipfr_timer_id",		0, 0, 0, 0 },
597255332Scy		{ "ipf_nat_lock",		0, 0, 0, 0 },		/* 30 */
598255332Scy		{ "ipf_rules",		0, 0, 0, 0 },
599255332Scy		{ "ipf_acct",		0, 0, 0, 0 },
600255332Scy		{ "ipl_frouteok",		0, 0, 0, 0 },
601255332Scy		{ "ipf_running",		0, 0, 0, 0 },
602255332Scy		{ "ipf_groups",		0, 0, 0, 0 },		/* 35 */
603255332Scy		{ "ipf_active",		0, 0, 0, 0 },
604255332Scy		{ "ipf_pass",		0, 0, 0, 0 },
605255332Scy		{ "ipf_flags",		0, 0, 0, 0 },
606255332Scy		{ "ipf_state_logging",		0, 0, 0, 0 },
607255332Scy		{ "ips_tqtqb",		0, 0, 0, 0 },		/* 40 */
608255332Scy		{ NULL,		0, 0, 0, 0 }
609145510Sdarrenr	};
610145510Sdarrenr
611145510Sdarrenr
612145510Sdarrenr	frauthstp = &frauthst;
613145510Sdarrenr	ipsstp = &ipsst;
614145510Sdarrenr	ifrstp = &ifrst;
615145510Sdarrenr	fiop = &fio;
616145510Sdarrenr
617145510Sdarrenr	*frfp = 0;
618145510Sdarrenr	*fiopp = fiop;
619145510Sdarrenr	*ipsstpp = ipsstp;
620145510Sdarrenr	*ifrstpp = ifrstp;
621145510Sdarrenr	*frauthstpp = frauthstp;
622145510Sdarrenr
623145510Sdarrenr	bzero((char *)fiop, sizeof(*fiop));
624145510Sdarrenr	bzero((char *)ipsstp, sizeof(*ipsstp));
625145510Sdarrenr	bzero((char *)ifrstp, sizeof(*ifrstp));
626145510Sdarrenr	bzero((char *)frauthstp, sizeof(*frauthstp));
627145510Sdarrenr
628145510Sdarrenr	if (nlist(kernel, deadlist) == -1) {
629145510Sdarrenr		fprintf(stderr, "nlist error\n");
630145510Sdarrenr		return;
631145510Sdarrenr	}
632145510Sdarrenr
633145510Sdarrenr	/*
634145510Sdarrenr	 * This is for SIOCGETFF.
635145510Sdarrenr	 */
636145510Sdarrenr	kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp));
637145510Sdarrenr
638145510Sdarrenr	/*
639145510Sdarrenr	 * f_locks is a combination of the lock variable from each part of
640145510Sdarrenr	 * ipfilter (state, auth, nat, fragments).
641145510Sdarrenr	 */
642145510Sdarrenr	kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop));
643145510Sdarrenr	kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value,
644145510Sdarrenr		sizeof(fiop->f_locks[0]));
645145510Sdarrenr	kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value,
646145510Sdarrenr		sizeof(fiop->f_locks[1]));
647145510Sdarrenr	kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value,
648145510Sdarrenr		sizeof(fiop->f_locks[2]));
649145510Sdarrenr	kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value,
650145510Sdarrenr		sizeof(fiop->f_locks[3]));
651145510Sdarrenr
652145510Sdarrenr	/*
653145510Sdarrenr	 * Get pointers to each list of rules (active, inactive, in, out)
654145510Sdarrenr	 */
655145510Sdarrenr	kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules));
656145510Sdarrenr	fiop->f_fin[0] = rules[0][0];
657145510Sdarrenr	fiop->f_fin[1] = rules[0][1];
658145510Sdarrenr	fiop->f_fout[0] = rules[1][0];
659145510Sdarrenr	fiop->f_fout[1] = rules[1][1];
660145510Sdarrenr
661145510Sdarrenr	/*
662145510Sdarrenr	 * Now get accounting rules pointers.
663145510Sdarrenr	 */
664145510Sdarrenr	kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules));
665145510Sdarrenr	fiop->f_acctin[0] = rules[0][0];
666145510Sdarrenr	fiop->f_acctin[1] = rules[0][1];
667145510Sdarrenr	fiop->f_acctout[0] = rules[1][0];
668145510Sdarrenr	fiop->f_acctout[1] = rules[1][1];
669145510Sdarrenr
670145510Sdarrenr	/*
671145510Sdarrenr	 * A collection of "global" variables used inside the kernel which
672145510Sdarrenr	 * are all collected in friostat_t via ioctl.
673145510Sdarrenr	 */
674255332Scy	kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[33].n_value,
675145510Sdarrenr		sizeof(fiop->f_froute));
676255332Scy	kmemcpy((char *)&fiop->f_running, (u_long)deadlist[34].n_value,
677145510Sdarrenr		sizeof(fiop->f_running));
678255332Scy	kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[35].n_value,
679145510Sdarrenr		sizeof(fiop->f_groups));
680255332Scy	kmemcpy((char *)&fiop->f_active, (u_long)deadlist[36].n_value,
681145510Sdarrenr		sizeof(fiop->f_active));
682255332Scy	kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[37].n_value,
683145510Sdarrenr		sizeof(fiop->f_defpass));
684145510Sdarrenr
685145510Sdarrenr	/*
686145510Sdarrenr	 * Build up the state information stats structure.
687145510Sdarrenr	 */
688145510Sdarrenr	kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp));
689145510Sdarrenr	kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp));
690255332Scy	kmemcpy((char *)ipstcptab, (u_long)deadlist[40].n_value,
691255332Scy		sizeof(ipstcptab));
692145510Sdarrenr	ipsstp->iss_active = temp;
693145510Sdarrenr	ipsstp->iss_table = (void *)deadlist[18].n_value;
694145510Sdarrenr	ipsstp->iss_list = (void *)deadlist[17].n_value;
695255332Scy	ipsstp->iss_tcptab = ipstcptab;
696145510Sdarrenr
697145510Sdarrenr	/*
698145510Sdarrenr	 * Build up the authentiation information stats structure.
699145510Sdarrenr	 */
700145510Sdarrenr	kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value,
701145510Sdarrenr		sizeof(*frauthstp));
702145510Sdarrenr	frauthstp->fas_faelist = (void *)deadlist[1].n_value;
703145510Sdarrenr
704145510Sdarrenr	/*
705145510Sdarrenr	 * Build up the fragment information stats structure.
706145510Sdarrenr	 */
707145510Sdarrenr	kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value,
708145510Sdarrenr		sizeof(*ifrstp));
709145510Sdarrenr	ifrstp->ifs_table = (void *)deadlist[23].n_value;
710145510Sdarrenr	ifrstp->ifs_nattab = (void *)deadlist[24].n_value;
711145510Sdarrenr	kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value,
712145510Sdarrenr		sizeof(ifrstp->ifs_inuse));
713145510Sdarrenr
714145510Sdarrenr	/*
715145510Sdarrenr	 * Get logging on/off switches
716145510Sdarrenr	 */
717145510Sdarrenr	kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value,
718145510Sdarrenr		sizeof(state_logging));
719145510Sdarrenr}
720145510Sdarrenr
721145510Sdarrenr
722255332Scystatic void printside(side, frs)
723255332Scy	char *side;
724255332Scy	ipf_statistics_t *frs;
725255332Scy{
726255332Scy	int i;
727255332Scy
728255332Scy	PRINTF("%lu\t%s bad packets\n", frs->fr_bad, side);
729255332Scy#ifdef	USE_INET6
730255332Scy	PRINTF("%lu\t%s IPv6 packets\n", frs->fr_ipv6, side);
731255332Scy#endif
732255332Scy	PRINTF("%lu\t%s packets blocked\n", frs->fr_block, side);
733255332Scy	PRINTF("%lu\t%s packets passed\n", frs->fr_pass, side);
734255332Scy	PRINTF("%lu\t%s packets not matched\n", frs->fr_nom, side);
735255332Scy	PRINTF("%lu\t%s packets counted\n", frs->fr_acct, side);
736255332Scy	PRINTF("%lu\t%s packets short\n", frs->fr_short, side);
737255332Scy	PRINTF("%lu\t%s packets logged and blocked\n", frs->fr_bpkl, side);
738255332Scy	PRINTF("%lu\t%s packets logged and passed\n", frs->fr_ppkl, side);
739255332Scy	PRINTF("%lu\t%s fragment state kept\n", frs->fr_nfr, side);
740255332Scy	PRINTF("%lu\t%s fragment state lost\n", frs->fr_bnfr, side);
741255332Scy	PRINTF("%lu\t%s packet state kept\n", frs->fr_ads, side);
742255332Scy	PRINTF("%lu\t%s packet state lost\n", frs->fr_bads, side);
743255332Scy	PRINTF("%lu\t%s invalid source\n", frs->fr_v4_badsrc, side);
744255332Scy	PRINTF("%lu\t%s cache hits\n", frs->fr_chit, side);
745255332Scy	PRINTF("%lu\t%s cache misses\n", frs->fr_cmiss, side);
746255332Scy	PRINTF("%lu\t%s bad coalesces\n", frs->fr_badcoalesces, side);
747255332Scy	PRINTF("%lu\t%s pullups succeeded\n", frs->fr_pull[0], side);
748255332Scy	PRINTF("%lu\t%s pullups failed\n", frs->fr_pull[1], side);
749255332Scy	PRINTF("%lu\t%s TCP checksum failures\n", frs->fr_tcpbad, side);
750255332Scy	for (i = 0; i <= FRB_MAX_VALUE; i++)
751255332Scy		PRINTF("%lu\t%s block reason %s\n",
752255332Scy			frs->fr_blocked[i], side, blockreasons[i]);
753255332Scy}
754255332Scy
755255332Scy
756145510Sdarrenr/*
757145510Sdarrenr * Display the kernel stats for packets blocked and passed and other
758145510Sdarrenr * associated running totals which are kept.
759145510Sdarrenr */
760145510Sdarrenrstatic	void	showstats(fp, frf)
761255332Scy	struct	friostat	*fp;
762255332Scy	u_32_t frf;
763145510Sdarrenr{
764255332Scy	printside("input", &fp->f_st[0]);
765255332Scy	printside("output", &fp->f_st[1]);
766145510Sdarrenr
767255332Scy	PRINTF("%lu\tpackets logged\n", fp->f_log_ok);
768255332Scy	PRINTF("%lu\tlog failures\n", fp->f_log_fail);
769255332Scy	PRINTF("%lu\tred-black no memory\n", fp->f_rb_no_mem);
770255332Scy	PRINTF("%lu\tred-black node maximum\n", fp->f_rb_node_max);
771255332Scy	PRINTF("%lu\tICMP replies sent\n", fp->f_st[0].fr_ret);
772255332Scy	PRINTF("%lu\tTCP RSTs sent\n", fp->f_st[1].fr_ret);
773255332Scy	PRINTF("%lu\tfastroute successes\n", fp->f_froute[0]);
774255332Scy	PRINTF("%lu\tfastroute failures\n", fp->f_froute[1]);
775255332Scy	PRINTF("%u\tIPF Ticks\n", fp->f_ticks);
776145510Sdarrenr
777255332Scy	PRINTF("%x\tPacket log flags set:\n", frf);
778145510Sdarrenr	if (frf & FF_LOGPASS)
779145510Sdarrenr		PRINTF("\tpackets passed through filter\n");
780145510Sdarrenr	if (frf & FF_LOGBLOCK)
781145510Sdarrenr		PRINTF("\tpackets blocked by filter\n");
782145510Sdarrenr	if (frf & FF_LOGNOMATCH)
783145510Sdarrenr		PRINTF("\tpackets not matched by filter\n");
784145510Sdarrenr	if (!frf)
785145510Sdarrenr		PRINTF("\tnone\n");
786145510Sdarrenr}
787145510Sdarrenr
788145510Sdarrenr
789145510Sdarrenr/*
790145510Sdarrenr * Print out a list of rules from the kernel, starting at the one passed.
791145510Sdarrenr */
792255332Scystatic int
793255332Scyprintlivelist(fiop, out, set, fp, group, comment)
794255332Scy	struct friostat *fiop;
795255332Scy	int out, set;
796255332Scy	frentry_t *fp;
797255332Scy	char *group, *comment;
798145510Sdarrenr{
799170268Sdarrenr	struct	frentry	fb;
800170268Sdarrenr	ipfruleiter_t rule;
801170268Sdarrenr	frentry_t zero;
802170268Sdarrenr	frgroup_t *g;
803170268Sdarrenr	ipfobj_t obj;
804255332Scy	int rules;
805255332Scy	int num;
806145510Sdarrenr
807255332Scy	rules = 0;
808170268Sdarrenr
809170268Sdarrenr	rule.iri_inout = out;
810170268Sdarrenr	rule.iri_active = set;
811170268Sdarrenr	rule.iri_rule = &fb;
812170268Sdarrenr	rule.iri_nrules = 1;
813170268Sdarrenr	if (group != NULL)
814170268Sdarrenr		strncpy(rule.iri_group, group, FR_GROUPLEN);
815170268Sdarrenr	else
816170268Sdarrenr		rule.iri_group[0] = '\0';
817170268Sdarrenr
818170268Sdarrenr	bzero((char *)&zero, sizeof(zero));
819170268Sdarrenr
820170268Sdarrenr	bzero((char *)&obj, sizeof(obj));
821170268Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
822170268Sdarrenr	obj.ipfo_type = IPFOBJ_IPFITER;
823170268Sdarrenr	obj.ipfo_size = sizeof(rule);
824170268Sdarrenr	obj.ipfo_ptr = &rule;
825170268Sdarrenr
826255332Scy	while (rule.iri_rule != NULL) {
827170268Sdarrenr		u_long array[1000];
828170268Sdarrenr
829170268Sdarrenr		memset(array, 0xff, sizeof(array));
830170268Sdarrenr		fp = (frentry_t *)array;
831170268Sdarrenr		rule.iri_rule = fp;
832170268Sdarrenr		if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) {
833255332Scy			ipferror(ipf_fd, "ioctl(SIOCIPFITER)");
834255332Scy			num = IPFGENITER_IPF;
835255332Scy			(void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
836255332Scy			return rules;
837145510Sdarrenr		}
838170268Sdarrenr		if (bcmp(fp, &zero, sizeof(zero)) == 0)
839170268Sdarrenr			break;
840255332Scy		if (rule.iri_rule == NULL)
841255332Scy			break;
842255332Scy#ifdef USE_INET6
843255332Scy		if (use_inet6 != 0) {
844255332Scy			if (fp->fr_family != 0 && fp->fr_family != AF_INET6)
845255332Scy				continue;
846255332Scy		} else
847255332Scy#endif
848255332Scy		{
849255332Scy			if (fp->fr_family != 0 && fp->fr_family != AF_INET)
850255332Scy				continue;
851255332Scy		}
852170268Sdarrenr		if (fp->fr_data != NULL)
853255332Scy			fp->fr_data = (char *)fp + fp->fr_size;
854170268Sdarrenr
855255332Scy		rules++;
856170268Sdarrenr
857255332Scy		if (opts & (OPT_HITS|OPT_DEBUG))
858145510Sdarrenr#ifdef	USE_QUAD_T
859255332Scy			PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_hits);
860145510Sdarrenr#else
861145510Sdarrenr			PRINTF("%lu ", fp->fr_hits);
862145510Sdarrenr#endif
863255332Scy		if (opts & (OPT_ACCNT|OPT_DEBUG))
864145510Sdarrenr#ifdef	USE_QUAD_T
865255332Scy			PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_bytes);
866145510Sdarrenr#else
867145510Sdarrenr			PRINTF("%lu ", fp->fr_bytes);
868145510Sdarrenr#endif
869145510Sdarrenr		if (opts & OPT_SHOWLINENO)
870255332Scy			PRINTF("@%d ", rules);
871170268Sdarrenr
872255332Scy		if (fp->fr_die != 0)
873255332Scy			fp->fr_die -= fiop->f_ticks;
874255332Scy
875170268Sdarrenr		printfr(fp, ioctl);
876170268Sdarrenr		if (opts & OPT_DEBUG) {
877255332Scy			binprint(fp, fp->fr_size);
878170268Sdarrenr			if (fp->fr_data != NULL && fp->fr_dsize > 0)
879170268Sdarrenr				binprint(fp->fr_data, fp->fr_dsize);
880170268Sdarrenr		}
881255332Scy		if (fp->fr_grhead != -1) {
882170268Sdarrenr			for (g = grtop; g != NULL; g = g->fg_next) {
883255332Scy				if (!strncmp(fp->fr_names + fp->fr_grhead,
884255332Scy					     g->fg_name,
885170268Sdarrenr					     FR_GROUPLEN))
886170268Sdarrenr					break;
887170268Sdarrenr			}
888170268Sdarrenr			if (g == NULL) {
889170268Sdarrenr				g = calloc(1, sizeof(*g));
890170268Sdarrenr
891170268Sdarrenr				if (g != NULL) {
892255332Scy					strncpy(g->fg_name,
893255332Scy						fp->fr_names + fp->fr_grhead,
894170268Sdarrenr						FR_GROUPLEN);
895170268Sdarrenr					if (grtop == NULL) {
896170268Sdarrenr						grtop = g;
897170268Sdarrenr						grtail = g;
898170268Sdarrenr					} else {
899170268Sdarrenr						grtail->fg_next = g;
900170268Sdarrenr						grtail = g;
901170268Sdarrenr					}
902170268Sdarrenr				}
903170268Sdarrenr			}
904170268Sdarrenr		}
905170268Sdarrenr		if (fp->fr_type == FR_T_CALLFUNC) {
906255332Scy			rules += printlivelist(fiop, out, set, fp->fr_data,
907255332Scy					       group, "# callfunc: ");
908170268Sdarrenr		}
909255332Scy	}
910170268Sdarrenr
911255332Scy	num = IPFGENITER_IPF;
912255332Scy	(void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
913170268Sdarrenr
914255332Scy	return rules;
915170268Sdarrenr}
916170268Sdarrenr
917170268Sdarrenr
918255332Scystatic void printdeadlist(fiop, out, set, fp, group, comment)
919255332Scy	friostat_t *fiop;
920255332Scy	int out, set;
921255332Scy	frentry_t *fp;
922255332Scy	char *group, *comment;
923170268Sdarrenr{
924170268Sdarrenr	frgroup_t *grtop, *grtail, *g;
925170268Sdarrenr	struct	frentry	fb;
926170268Sdarrenr	char	*data;
927170268Sdarrenr	u_32_t	type;
928170268Sdarrenr	int	n;
929170268Sdarrenr
930170268Sdarrenr	fb.fr_next = fp;
931170268Sdarrenr	n = 0;
932170268Sdarrenr	grtop = NULL;
933170268Sdarrenr	grtail = NULL;
934170268Sdarrenr
935255332Scy	for (n = 1; fp; fp = fb.fr_next, n++) {
936170268Sdarrenr		if (kmemcpy((char *)&fb, (u_long)fb.fr_next,
937255332Scy			    fb.fr_size) == -1) {
938170268Sdarrenr			perror("kmemcpy");
939170268Sdarrenr			return;
940170268Sdarrenr		}
941255332Scy		fp = &fb;
942255332Scy		if (use_inet6 != 0) {
943255332Scy			if (fp->fr_family != 0 && fp->fr_family != 6)
944255332Scy				continue;
945255332Scy		} else {
946255332Scy			if (fp->fr_family != 0 && fp->fr_family != 4)
947255332Scy				continue;
948255332Scy		}
949170268Sdarrenr
950145510Sdarrenr		data = NULL;
951170268Sdarrenr		type = fb.fr_type & ~FR_T_BUILTIN;
952145510Sdarrenr		if (type == FR_T_IPF || type == FR_T_BPFOPC) {
953170268Sdarrenr			if (fb.fr_dsize) {
954170268Sdarrenr				data = malloc(fb.fr_dsize);
955145510Sdarrenr
956170268Sdarrenr				if (kmemcpy(data, (u_long)fb.fr_data,
957170268Sdarrenr					    fb.fr_dsize) == -1) {
958145510Sdarrenr					perror("kmemcpy");
959145510Sdarrenr					return;
960145510Sdarrenr				}
961170268Sdarrenr				fb.fr_data = data;
962145510Sdarrenr			}
963145510Sdarrenr		}
964145510Sdarrenr
965255332Scy		if (opts & OPT_HITS)
966170268Sdarrenr#ifdef	USE_QUAD_T
967255332Scy			PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_hits);
968170268Sdarrenr#else
969170268Sdarrenr			PRINTF("%lu ", fb.fr_hits);
970170268Sdarrenr#endif
971255332Scy		if (opts & OPT_ACCNT)
972170268Sdarrenr#ifdef	USE_QUAD_T
973255332Scy			PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_bytes);
974170268Sdarrenr#else
975170268Sdarrenr			PRINTF("%lu ", fb.fr_bytes);
976170268Sdarrenr#endif
977170268Sdarrenr		if (opts & OPT_SHOWLINENO)
978170268Sdarrenr			PRINTF("@%d ", n);
979170268Sdarrenr
980145510Sdarrenr		printfr(fp, ioctl);
981145510Sdarrenr		if (opts & OPT_DEBUG) {
982255332Scy			binprint(fp, fp->fr_size);
983170268Sdarrenr			if (fb.fr_data != NULL && fb.fr_dsize > 0)
984170268Sdarrenr				binprint(fb.fr_data, fb.fr_dsize);
985145510Sdarrenr		}
986145510Sdarrenr		if (data != NULL)
987145510Sdarrenr			free(data);
988255332Scy		if (fb.fr_grhead != -1) {
989170268Sdarrenr			g = calloc(1, sizeof(*g));
990170268Sdarrenr
991170268Sdarrenr			if (g != NULL) {
992255332Scy				strncpy(g->fg_name, fb.fr_names + fb.fr_grhead,
993170268Sdarrenr					FR_GROUPLEN);
994170268Sdarrenr				if (grtop == NULL) {
995170268Sdarrenr					grtop = g;
996170268Sdarrenr					grtail = g;
997170268Sdarrenr				} else {
998170268Sdarrenr					grtail->fg_next = g;
999170268Sdarrenr					grtail = g;
1000170268Sdarrenr				}
1001170268Sdarrenr			}
1002145510Sdarrenr		}
1003145510Sdarrenr		if (type == FR_T_CALLFUNC) {
1004255332Scy			printdeadlist(fiop, out, set, fb.fr_data, group,
1005170268Sdarrenr				      "# callfunc: ");
1006145510Sdarrenr		}
1007255332Scy	}
1008170268Sdarrenr
1009170268Sdarrenr	while ((g = grtop) != NULL) {
1010255332Scy		printdeadlist(fiop, out, set, NULL, g->fg_name, comment);
1011170268Sdarrenr		grtop = g->fg_next;
1012170268Sdarrenr		free(g);
1013145510Sdarrenr	}
1014145510Sdarrenr}
1015145510Sdarrenr
1016145510Sdarrenr/*
1017145510Sdarrenr * print out all of the asked for rule sets, using the stats struct as
1018145510Sdarrenr * the base from which to get the pointers.
1019145510Sdarrenr */
1020145510Sdarrenrstatic	void	showlist(fiop)
1021255332Scy	struct	friostat	*fiop;
1022145510Sdarrenr{
1023145510Sdarrenr	struct	frentry	*fp = NULL;
1024145510Sdarrenr	int	i, set;
1025145510Sdarrenr
1026145510Sdarrenr	set = fiop->f_active;
1027145510Sdarrenr	if (opts & OPT_INACTIVE)
1028145510Sdarrenr		set = 1 - set;
1029145510Sdarrenr	if (opts & OPT_ACCNT) {
1030145510Sdarrenr		if (opts & OPT_OUTQUE) {
1031145510Sdarrenr			i = F_ACOUT;
1032145510Sdarrenr			fp = (struct frentry *)fiop->f_acctout[set];
1033145510Sdarrenr		} else if (opts & OPT_INQUE) {
1034145510Sdarrenr			i = F_ACIN;
1035145510Sdarrenr			fp = (struct frentry *)fiop->f_acctin[set];
1036145510Sdarrenr		} else {
1037145510Sdarrenr			FPRINTF(stderr, "No -i or -o given with -a\n");
1038145510Sdarrenr			return;
1039145510Sdarrenr		}
1040145510Sdarrenr	} else {
1041145510Sdarrenr		if (opts & OPT_OUTQUE) {
1042145510Sdarrenr			i = F_OUT;
1043145510Sdarrenr			fp = (struct frentry *)fiop->f_fout[set];
1044145510Sdarrenr		} else if (opts & OPT_INQUE) {
1045145510Sdarrenr			i = F_IN;
1046145510Sdarrenr			fp = (struct frentry *)fiop->f_fin[set];
1047145510Sdarrenr		} else
1048145510Sdarrenr			return;
1049145510Sdarrenr	}
1050170268Sdarrenr	if (opts & OPT_DEBUG)
1051145510Sdarrenr		FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
1052145510Sdarrenr
1053170268Sdarrenr	if (opts & OPT_DEBUG)
1054145510Sdarrenr		PRINTF("fp %p set %d\n", fp, set);
1055255332Scy
1056255332Scy	if (live_kernel == 1) {
1057255332Scy		int printed;
1058255332Scy
1059255332Scy		printed = printlivelist(fiop, i, set, fp, NULL, NULL);
1060255332Scy		if (printed == 0) {
1061255332Scy			FPRINTF(stderr, "# empty list for %s%s\n",
1062255332Scy			        (opts & OPT_INACTIVE) ? "inactive " : "",
1063255332Scy							filters[i]);
1064255332Scy		}
1065255332Scy	} else {
1066255332Scy		if (!fp) {
1067255332Scy			FPRINTF(stderr, "# empty list for %s%s\n",
1068255332Scy			        (opts & OPT_INACTIVE) ? "inactive " : "",
1069255332Scy							filters[i]);
1070255332Scy		} else {
1071255332Scy			printdeadlist(fiop, i, set, fp, NULL, NULL);
1072255332Scy		}
1073145510Sdarrenr	}
1074145510Sdarrenr}
1075145510Sdarrenr
1076145510Sdarrenr
1077145510Sdarrenr/*
1078145510Sdarrenr * Display ipfilter stateful filtering information
1079145510Sdarrenr */
1080255332Scystatic void showipstates(ipsp, filter)
1081255332Scy	ips_stat_t *ipsp;
1082255332Scy	int *filter;
1083145510Sdarrenr{
1084255332Scy	ipstate_t *is;
1085255332Scy	int i;
1086145510Sdarrenr
1087145510Sdarrenr	/*
1088145510Sdarrenr	 * If a list of states hasn't been asked for, only print out stats
1089145510Sdarrenr	 */
1090145510Sdarrenr	if (!(opts & OPT_SHOWLIST)) {
1091255332Scy		showstatestats(ipsp);
1092255332Scy		return;
1093255332Scy	}
1094170268Sdarrenr
1095255332Scy	if ((state_fields != NULL) && (nohdrfields == 0)) {
1096255332Scy		for (i = 0; state_fields[i].w_value != 0; i++) {
1097255332Scy			printfieldhdr(statefields, state_fields + i);
1098255332Scy			if (state_fields[i + 1].w_value != 0)
1099255332Scy				printf("\t");
1100255332Scy		}
1101255332Scy		printf("\n");
1102255332Scy	}
1103170268Sdarrenr
1104255332Scy	/*
1105255332Scy	 * Print out all the state information currently held in the kernel.
1106255332Scy	 */
1107255332Scy	for (is = ipsp->iss_list; is != NULL; ) {
1108255332Scy		ipstate_t ips;
1109170268Sdarrenr
1110255332Scy		is = fetchstate(is, &ips);
1111170268Sdarrenr
1112255332Scy		if (is == NULL)
1113255332Scy			break;
1114255332Scy
1115255332Scy		is = ips.is_next;
1116255332Scy		if ((filter != NULL) &&
1117255332Scy		    (state_matcharray(&ips, filter) == 0)) {
1118255332Scy			continue;
1119255332Scy		}
1120255332Scy		if (state_fields != NULL) {
1121255332Scy			for (i = 0; state_fields[i].w_value != 0; i++) {
1122255332Scy				printstatefield(&ips, state_fields[i].w_value);
1123255332Scy				if (state_fields[i + 1].w_value != 0)
1124255332Scy					printf("\t");
1125170268Sdarrenr			}
1126255332Scy			printf("\n");
1127170268Sdarrenr		} else {
1128255332Scy			printstate(&ips, opts, ipsp->iss_ticks);
1129170268Sdarrenr		}
1130255332Scy	}
1131255332Scy}
1132170268Sdarrenr
1133145510Sdarrenr
1134255332Scystatic void showstatestats(ipsp)
1135255332Scy	ips_stat_t *ipsp;
1136255332Scy{
1137255332Scy	int minlen, maxlen, totallen;
1138255332Scy	ipftable_t table;
1139255332Scy	u_int *buckets;
1140255332Scy	ipfobj_t obj;
1141255332Scy	int i, sz;
1142145510Sdarrenr
1143255332Scy	/*
1144255332Scy	 * If a list of states hasn't been asked for, only print out stats
1145255332Scy	 */
1146145510Sdarrenr
1147255332Scy	sz = sizeof(*buckets) * ipsp->iss_state_size;
1148255332Scy	buckets = (u_int *)malloc(sz);
1149145510Sdarrenr
1150255332Scy	obj.ipfo_rev = IPFILTER_VERSION;
1151255332Scy	obj.ipfo_type = IPFOBJ_GTABLE;
1152255332Scy	obj.ipfo_size = sizeof(table);
1153255332Scy	obj.ipfo_ptr = &table;
1154255332Scy
1155255332Scy	table.ita_type = IPFTABLE_BUCKETS;
1156255332Scy	table.ita_table = buckets;
1157255332Scy
1158255332Scy	if (live_kernel == 1) {
1159255332Scy		if (ioctl(state_fd, SIOCGTABL, &obj) != 0) {
1160255332Scy			free(buckets);
1161255332Scy			return;
1162145510Sdarrenr		}
1163255332Scy	} else {
1164255332Scy		if (kmemcpy((char *)buckets,
1165255332Scy			    (u_long)ipsp->iss_bucketlen, sz)) {
1166255332Scy			free(buckets);
1167255332Scy			return;
1168255332Scy		}
1169255332Scy	}
1170145510Sdarrenr
1171255332Scy	PRINTF("%u\tactive state table entries\n",ipsp->iss_active);
1172255332Scy	PRINTF("%lu\tadd bad\n", ipsp->iss_add_bad);
1173255332Scy	PRINTF("%lu\tadd duplicate\n", ipsp->iss_add_dup);
1174255332Scy	PRINTF("%lu\tadd locked\n", ipsp->iss_add_locked);
1175255332Scy	PRINTF("%lu\tadd oow\n", ipsp->iss_add_oow);
1176255332Scy	PRINTF("%lu\tbucket full\n", ipsp->iss_bucket_full);
1177255332Scy	PRINTF("%lu\tcheck bad\n", ipsp->iss_check_bad);
1178255332Scy	PRINTF("%lu\tcheck miss\n", ipsp->iss_check_miss);
1179255332Scy	PRINTF("%lu\tcheck nattag\n", ipsp->iss_check_nattag);
1180255332Scy	PRINTF("%lu\tclone nomem\n", ipsp->iss_clone_nomem);
1181255332Scy	PRINTF("%lu\tcheck notag\n", ipsp->iss_check_notag);
1182255332Scy	PRINTF("%lu\tcheck success\n", ipsp->iss_hits);
1183255332Scy	PRINTF("%lu\tcloned\n", ipsp->iss_cloned);
1184255332Scy	PRINTF("%lu\texpired\n", ipsp->iss_expire);
1185255332Scy	PRINTF("%lu\tflush all\n", ipsp->iss_flush_all);
1186255332Scy	PRINTF("%lu\tflush closing\n", ipsp->iss_flush_closing);
1187255332Scy	PRINTF("%lu\tflush queue\n", ipsp->iss_flush_queue);
1188255332Scy	PRINTF("%lu\tflush state\n", ipsp->iss_flush_state);
1189255332Scy	PRINTF("%lu\tflush timeout\n", ipsp->iss_flush_timeout);
1190255332Scy	PRINTF("%u\thash buckets in use\n", ipsp->iss_inuse);
1191255332Scy	PRINTF("%lu\tICMP bad\n", ipsp->iss_icmp_bad);
1192255332Scy	PRINTF("%lu\tICMP banned\n", ipsp->iss_icmp_banned);
1193255332Scy	PRINTF("%lu\tICMP errors\n", ipsp->iss_icmp_icmperr);
1194255332Scy	PRINTF("%lu\tICMP head block\n", ipsp->iss_icmp_headblock);
1195255332Scy	PRINTF("%lu\tICMP hits\n", ipsp->iss_icmp_hits);
1196255332Scy	PRINTF("%lu\tICMP not query\n",	ipsp->iss_icmp_notquery);
1197255332Scy	PRINTF("%lu\tICMP short\n", ipsp->iss_icmp_short);
1198255332Scy	PRINTF("%lu\tICMP too many\n", ipsp->iss_icmp_toomany);
1199255332Scy	PRINTF("%lu\tICMPv6 errors\n", ipsp->iss_icmp6_icmperr);
1200255332Scy	PRINTF("%lu\tICMPv6 miss\n", ipsp->iss_icmp6_miss);
1201255332Scy	PRINTF("%lu\tICMPv6 not info\n", ipsp->iss_icmp6_notinfo);
1202255332Scy	PRINTF("%lu\tICMPv6 not query\n", ipsp->iss_icmp6_notquery);
1203255332Scy	PRINTF("%lu\tlog fail\n", ipsp->iss_log_fail);
1204255332Scy	PRINTF("%lu\tlog ok\n", ipsp->iss_log_ok);
1205255332Scy	PRINTF("%lu\tlookup interface mismatch\n", ipsp->iss_lookup_badifp);
1206255332Scy	PRINTF("%lu\tlookup mask mismatch\n", ipsp->iss_miss_mask);
1207255332Scy	PRINTF("%lu\tlookup port mismatch\n", ipsp->iss_lookup_badport);
1208255332Scy	PRINTF("%lu\tlookup miss\n", ipsp->iss_lookup_miss);
1209255332Scy	PRINTF("%lu\tmaximum rule references\n", ipsp->iss_max_ref);
1210255332Scy	PRINTF("%lu\tmaximum hosts per rule\n", ipsp->iss_max_track);
1211255332Scy	PRINTF("%lu\tno memory\n", ipsp->iss_nomem);
1212255332Scy	PRINTF("%lu\tout of window\n", ipsp->iss_oow);
1213255332Scy	PRINTF("%lu\torphans\n", ipsp->iss_orphan);
1214255332Scy	PRINTF("%lu\tscan block\n", ipsp->iss_scan_block);
1215255332Scy	PRINTF("%lu\tstate table maximum reached\n", ipsp->iss_max);
1216255332Scy	PRINTF("%lu\tTCP closing\n", ipsp->iss_tcp_closing);
1217255332Scy	PRINTF("%lu\tTCP OOW\n", ipsp->iss_tcp_oow);
1218255332Scy	PRINTF("%lu\tTCP RST add\n", ipsp->iss_tcp_rstadd);
1219255332Scy	PRINTF("%lu\tTCP too small\n", ipsp->iss_tcp_toosmall);
1220255332Scy	PRINTF("%lu\tTCP bad options\n", ipsp->iss_tcp_badopt);
1221255332Scy	PRINTF("%lu\tTCP removed\n", ipsp->iss_fin);
1222255332Scy	PRINTF("%lu\tTCP FSM\n", ipsp->iss_tcp_fsm);
1223255332Scy	PRINTF("%lu\tTCP strict\n", ipsp->iss_tcp_strict);
1224255332Scy	PRINTF("%lu\tTCP wild\n", ipsp->iss_wild);
1225255332Scy	PRINTF("%lu\tMicrosoft Windows SACK\n", ipsp->iss_winsack);
1226145510Sdarrenr
1227255332Scy	PRINTF("State logging %sabled\n", state_logging ? "en" : "dis");
1228145510Sdarrenr
1229255332Scy	PRINTF("IP states added:\n");
1230255332Scy	for (i = 0; i < 256; i++) {
1231255332Scy		if (ipsp->iss_proto[i] != 0) {
1232255332Scy			struct protoent *proto;
1233255332Scy
1234255332Scy			proto = getprotobynumber(i);
1235255332Scy			PRINTF("%lu", ipsp->iss_proto[i]);
1236255332Scy			if (proto != NULL)
1237255332Scy				PRINTF("\t%s\n", proto->p_name);
1238255332Scy			else
1239255332Scy				PRINTF("\t%d\n", i);
1240145510Sdarrenr		}
1241255332Scy	}
1242145510Sdarrenr
1243255332Scy	PRINTF("\nState table bucket statistics:\n");
1244255332Scy	PRINTF("%u\tin use\n", ipsp->iss_inuse);
1245170268Sdarrenr
1246255332Scy	minlen = ipsp->iss_max;
1247255332Scy	totallen = 0;
1248255332Scy	maxlen = 0;
1249170268Sdarrenr
1250255332Scy	for (i = 0; i < ipsp->iss_state_size; i++) {
1251255332Scy		if (buckets[i] > maxlen)
1252255332Scy			maxlen = buckets[i];
1253255332Scy		if (buckets[i] < minlen)
1254255332Scy			minlen = buckets[i];
1255255332Scy		totallen += buckets[i];
1256145510Sdarrenr	}
1257145510Sdarrenr
1258255332Scy	PRINTF("%d\thash efficiency\n",
1259255332Scy		totallen ? ipsp->iss_inuse * 100 / totallen : 0);
1260255332Scy	PRINTF("%2.2f%%\tbucket usage\n%u\tminimal length\n",
1261255332Scy		((float)ipsp->iss_inuse / ipsp->iss_state_size) * 100.0,
1262255332Scy		minlen);
1263255332Scy	PRINTF("%u\tmaximal length\n%.3f\taverage length\n",
1264255332Scy		maxlen,
1265255332Scy		ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse :
1266255332Scy				  0.0);
1267170268Sdarrenr
1268255332Scy#define ENTRIES_PER_LINE 5
1269170268Sdarrenr
1270255332Scy	if (opts & OPT_VERBOSE) {
1271255332Scy		PRINTF("\nCurrent bucket sizes :\n");
1272255332Scy		for (i = 0; i < ipsp->iss_state_size; i++) {
1273255332Scy			if ((i % ENTRIES_PER_LINE) == 0)
1274255332Scy				PRINTF("\t");
1275255332Scy			PRINTF("%4d -> %4u", i, buckets[i]);
1276255332Scy			if ((i % ENTRIES_PER_LINE) ==
1277255332Scy			    (ENTRIES_PER_LINE - 1))
1278255332Scy				PRINTF("\n");
1279255332Scy			else
1280255332Scy				PRINTF("  ");
1281170268Sdarrenr		}
1282255332Scy		PRINTF("\n");
1283145510Sdarrenr	}
1284255332Scy	PRINTF("\n");
1285255332Scy
1286255332Scy	free(buckets);
1287255332Scy
1288255332Scy	if (live_kernel == 1) {
1289255332Scy		showtqtable_live(state_fd);
1290255332Scy	} else {
1291255332Scy		printtqtable(ipsp->iss_tcptab);
1292255332Scy	}
1293145510Sdarrenr}
1294145510Sdarrenr
1295145510Sdarrenr
1296145510Sdarrenr#ifdef STATETOP
1297145510Sdarrenrstatic int handle_resize = 0, handle_break = 0;
1298145510Sdarrenr
1299145510Sdarrenrstatic void topipstates(saddr, daddr, sport, dport, protocol, ver,
1300255332Scy		        refreshtime, topclosed, filter)
1301255332Scy	i6addr_t saddr;
1302255332Scy	i6addr_t daddr;
1303255332Scy	int sport;
1304255332Scy	int dport;
1305255332Scy	int protocol;
1306255332Scy	int ver;
1307255332Scy	int refreshtime;
1308255332Scy	int topclosed;
1309255332Scy	int *filter;
1310145510Sdarrenr{
1311145510Sdarrenr	char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
1312145510Sdarrenr	int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
1313153881Sguido	int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0;
1314145510Sdarrenr	int len, srclen, dstlen, forward = 1, c = 0;
1315145510Sdarrenr	ips_stat_t ipsst, *ipsstp = &ipsst;
1316255332Scy	int token_type = IPFGENITER_STATE;
1317145510Sdarrenr	statetop_t *tstable = NULL, *tp;
1318153881Sguido	const char *errstr = "";
1319145510Sdarrenr	ipstate_t ips;
1320145510Sdarrenr	ipfobj_t ipfo;
1321145510Sdarrenr	struct timeval selecttimeout;
1322145510Sdarrenr	char hostnm[HOSTNMLEN];
1323145510Sdarrenr	struct protoent *proto;
1324145510Sdarrenr	fd_set readfd;
1325145510Sdarrenr	time_t t;
1326145510Sdarrenr
1327145510Sdarrenr	/* install signal handlers */
1328145510Sdarrenr	signal(SIGINT, sig_break);
1329145510Sdarrenr	signal(SIGQUIT, sig_break);
1330145510Sdarrenr	signal(SIGTERM, sig_break);
1331145510Sdarrenr	signal(SIGWINCH, sig_resize);
1332145510Sdarrenr
1333145510Sdarrenr	/* init ncurses stuff */
1334145510Sdarrenr  	initscr();
1335145510Sdarrenr  	cbreak();
1336145510Sdarrenr  	noecho();
1337145510Sdarrenr	curs_set(0);
1338145510Sdarrenr	timeout(0);
1339145510Sdarrenr	getmaxyx(stdscr, maxy, maxx);
1340145510Sdarrenr
1341145510Sdarrenr	/* init hostname */
1342145510Sdarrenr	gethostname(hostnm, sizeof(hostnm) - 1);
1343145510Sdarrenr	hostnm[sizeof(hostnm) - 1] = '\0';
1344145510Sdarrenr
1345145510Sdarrenr	/* init ipfobj_t stuff */
1346145510Sdarrenr	bzero((caddr_t)&ipfo, sizeof(ipfo));
1347145510Sdarrenr	ipfo.ipfo_rev = IPFILTER_VERSION;
1348170268Sdarrenr	ipfo.ipfo_type = IPFOBJ_STATESTAT;
1349145510Sdarrenr	ipfo.ipfo_size = sizeof(*ipsstp);
1350145510Sdarrenr	ipfo.ipfo_ptr = (void *)ipsstp;
1351145510Sdarrenr
1352145510Sdarrenr	/* repeat until user aborts */
1353145510Sdarrenr	while ( 1 ) {
1354145510Sdarrenr
1355145510Sdarrenr		/* get state table */
1356145510Sdarrenr		bzero((char *)&ipsst, sizeof(ipsst));
1357145510Sdarrenr		if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
1358153881Sguido			errstr = "ioctl(SIOCGETFS)";
1359153881Sguido			ret = -1;
1360153881Sguido			goto out;
1361145510Sdarrenr		}
1362145510Sdarrenr
1363145510Sdarrenr		/* clear the history */
1364145510Sdarrenr		tsentry = -1;
1365145510Sdarrenr
1366145510Sdarrenr		/* reset max str len */
1367145510Sdarrenr		srclen = dstlen = 0;
1368145510Sdarrenr
1369145510Sdarrenr		/* read the state table and store in tstable */
1370145510Sdarrenr		for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
1371145510Sdarrenr
1372170268Sdarrenr			ipsstp->iss_list = fetchstate(ipsstp->iss_list, &ips);
1373170268Sdarrenr			if (ipsstp->iss_list == NULL)
1374145510Sdarrenr				break;
1375145510Sdarrenr
1376145510Sdarrenr			if (ips.is_v != ver)
1377145510Sdarrenr				continue;
1378145510Sdarrenr
1379255332Scy			if ((filter != NULL) &&
1380255332Scy			    (state_matcharray(&ips, filter) == 0))
1381255332Scy				continue;
1382255332Scy
1383145510Sdarrenr			/* check v4 src/dest addresses */
1384145510Sdarrenr			if (ips.is_v == 4) {
1385145510Sdarrenr				if ((saddr.in4.s_addr != INADDR_ANY &&
1386145510Sdarrenr				     saddr.in4.s_addr != ips.is_saddr) ||
1387145510Sdarrenr				    (daddr.in4.s_addr != INADDR_ANY &&
1388145510Sdarrenr				     daddr.in4.s_addr != ips.is_daddr))
1389145510Sdarrenr					continue;
1390145510Sdarrenr			}
1391145510Sdarrenr#ifdef	USE_INET6
1392145510Sdarrenr			/* check v6 src/dest addresses */
1393145510Sdarrenr			if (ips.is_v == 6) {
1394145510Sdarrenr				if ((IP6_NEQ(&saddr, &in6addr_any) &&
1395145510Sdarrenr				     IP6_NEQ(&saddr, &ips.is_src)) ||
1396145510Sdarrenr				    (IP6_NEQ(&daddr, &in6addr_any) &&
1397145510Sdarrenr				     IP6_NEQ(&daddr, &ips.is_dst)))
1398145510Sdarrenr					continue;
1399145510Sdarrenr			}
1400145510Sdarrenr#endif
1401145510Sdarrenr			/* check protocol */
1402145510Sdarrenr			if (protocol > 0 && protocol != ips.is_p)
1403145510Sdarrenr				continue;
1404145510Sdarrenr
1405145510Sdarrenr			/* check ports if protocol is TCP or UDP */
1406145510Sdarrenr			if (((ips.is_p == IPPROTO_TCP) ||
1407145510Sdarrenr			     (ips.is_p == IPPROTO_UDP)) &&
1408145510Sdarrenr			   (((sport > 0) && (htons(sport) != ips.is_sport)) ||
1409145510Sdarrenr			    ((dport > 0) && (htons(dport) != ips.is_dport))))
1410145510Sdarrenr				continue;
1411145510Sdarrenr
1412145510Sdarrenr			/* show closed TCP sessions ? */
1413145510Sdarrenr			if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
1414145510Sdarrenr			    (ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
1415145510Sdarrenr			    (ips.is_state[1] >= IPF_TCPS_LAST_ACK))
1416145510Sdarrenr				continue;
1417145510Sdarrenr
1418145510Sdarrenr			/*
1419145510Sdarrenr			 * if necessary make room for this state
1420145510Sdarrenr			 * entry
1421145510Sdarrenr			 */
1422145510Sdarrenr			tsentry++;
1423145510Sdarrenr			if (!maxtsentries || tsentry == maxtsentries) {
1424145510Sdarrenr				maxtsentries += STGROWSIZE;
1425145510Sdarrenr				tstable = realloc(tstable,
1426145510Sdarrenr				    maxtsentries * sizeof(statetop_t));
1427145510Sdarrenr				if (tstable == NULL) {
1428145510Sdarrenr					perror("realloc");
1429145510Sdarrenr					exit(-1);
1430145510Sdarrenr				}
1431145510Sdarrenr			}
1432145510Sdarrenr
1433145510Sdarrenr			/* get max src/dest address string length */
1434145510Sdarrenr			len = strlen(getip(ips.is_v, &ips.is_src));
1435145510Sdarrenr			if (srclen < len)
1436145510Sdarrenr				srclen = len;
1437145510Sdarrenr			len = strlen(getip(ips.is_v, &ips.is_dst));
1438145510Sdarrenr			if (dstlen < len)
1439145510Sdarrenr				dstlen = len;
1440145510Sdarrenr
1441145510Sdarrenr			/* fill structure */
1442145510Sdarrenr			tp = tstable + tsentry;
1443145510Sdarrenr			tp->st_src = ips.is_src;
1444145510Sdarrenr			tp->st_dst = ips.is_dst;
1445145510Sdarrenr			tp->st_p = ips.is_p;
1446145510Sdarrenr			tp->st_v = ips.is_v;
1447145510Sdarrenr			tp->st_state[0] = ips.is_state[0];
1448145510Sdarrenr			tp->st_state[1] = ips.is_state[1];
1449145510Sdarrenr			if (forward) {
1450145510Sdarrenr				tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
1451145510Sdarrenr				tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
1452145510Sdarrenr			} else {
1453145510Sdarrenr				tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3];
1454145510Sdarrenr				tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3];
1455145510Sdarrenr			}
1456145510Sdarrenr			tp->st_age = ips.is_die - ipsstp->iss_ticks;
1457145510Sdarrenr			if ((ips.is_p == IPPROTO_TCP) ||
1458145510Sdarrenr			    (ips.is_p == IPPROTO_UDP)) {
1459145510Sdarrenr				tp->st_sport = ips.is_sport;
1460145510Sdarrenr				tp->st_dport = ips.is_dport;
1461145510Sdarrenr			}
1462145510Sdarrenr		}
1463145510Sdarrenr
1464255332Scy		(void) ioctl(state_fd, SIOCIPFDELTOK, &token_type);
1465145510Sdarrenr
1466145510Sdarrenr		/* sort the array */
1467145510Sdarrenr		if (tsentry != -1) {
1468145510Sdarrenr			switch (sorting)
1469145510Sdarrenr			{
1470145510Sdarrenr			case STSORT_PR:
1471145510Sdarrenr				qsort(tstable, tsentry + 1,
1472145510Sdarrenr				      sizeof(statetop_t), sort_p);
1473145510Sdarrenr				break;
1474145510Sdarrenr			case STSORT_PKTS:
1475145510Sdarrenr				qsort(tstable, tsentry + 1,
1476145510Sdarrenr				      sizeof(statetop_t), sort_pkts);
1477145510Sdarrenr				break;
1478145510Sdarrenr			case STSORT_BYTES:
1479145510Sdarrenr				qsort(tstable, tsentry + 1,
1480145510Sdarrenr				      sizeof(statetop_t), sort_bytes);
1481145510Sdarrenr				break;
1482145510Sdarrenr			case STSORT_TTL:
1483145510Sdarrenr				qsort(tstable, tsentry + 1,
1484145510Sdarrenr				      sizeof(statetop_t), sort_ttl);
1485145510Sdarrenr				break;
1486145510Sdarrenr			case STSORT_SRCIP:
1487145510Sdarrenr				qsort(tstable, tsentry + 1,
1488145510Sdarrenr				      sizeof(statetop_t), sort_srcip);
1489145510Sdarrenr				break;
1490145510Sdarrenr			case STSORT_SRCPT:
1491145510Sdarrenr				qsort(tstable, tsentry +1,
1492145510Sdarrenr					sizeof(statetop_t), sort_srcpt);
1493145510Sdarrenr				break;
1494145510Sdarrenr			case STSORT_DSTIP:
1495145510Sdarrenr				qsort(tstable, tsentry + 1,
1496145510Sdarrenr				      sizeof(statetop_t), sort_dstip);
1497145510Sdarrenr				break;
1498145510Sdarrenr			case STSORT_DSTPT:
1499145510Sdarrenr				qsort(tstable, tsentry + 1,
1500145510Sdarrenr				      sizeof(statetop_t), sort_dstpt);
1501145510Sdarrenr				break;
1502145510Sdarrenr			default:
1503145510Sdarrenr				break;
1504145510Sdarrenr			}
1505145510Sdarrenr		}
1506145510Sdarrenr
1507145510Sdarrenr		/* handle window resizes */
1508145510Sdarrenr		if (handle_resize) {
1509145510Sdarrenr			endwin();
1510145510Sdarrenr			initscr();
1511145510Sdarrenr			cbreak();
1512145510Sdarrenr			noecho();
1513145510Sdarrenr			curs_set(0);
1514145510Sdarrenr			timeout(0);
1515145510Sdarrenr			getmaxyx(stdscr, maxy, maxx);
1516145510Sdarrenr			redraw = 1;
1517145510Sdarrenr			handle_resize = 0;
1518145510Sdarrenr                }
1519145510Sdarrenr
1520145510Sdarrenr		/* stop program? */
1521145510Sdarrenr		if (handle_break)
1522145510Sdarrenr			break;
1523145510Sdarrenr
1524145510Sdarrenr		/* print title */
1525145510Sdarrenr		erase();
1526145510Sdarrenr		attron(A_BOLD);
1527145510Sdarrenr		winy = 0;
1528145510Sdarrenr		move(winy,0);
1529145510Sdarrenr		sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION);
1530145510Sdarrenr		for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
1531145510Sdarrenr			printw(" ");
1532145510Sdarrenr		printw("%s", str1);
1533145510Sdarrenr		attroff(A_BOLD);
1534145510Sdarrenr
1535145510Sdarrenr		/* just for fun add a clock */
1536145510Sdarrenr		move(winy, maxx - 8);
1537145510Sdarrenr		t = time(NULL);
1538145510Sdarrenr		strftime(str1, 80, "%T", localtime(&t));
1539145510Sdarrenr		printw("%s\n", str1);
1540145510Sdarrenr
1541145510Sdarrenr		/*
1542145510Sdarrenr		 * print the display filters, this is placed in the loop,
1543145510Sdarrenr		 * because someday I might add code for changing these
1544145510Sdarrenr		 * while the programming is running :-)
1545145510Sdarrenr		 */
1546145510Sdarrenr		if (sport >= 0)
1547145510Sdarrenr			sprintf(str1, "%s,%d", getip(ver, &saddr), sport);
1548145510Sdarrenr		else
1549145510Sdarrenr			sprintf(str1, "%s", getip(ver, &saddr));
1550145510Sdarrenr
1551145510Sdarrenr		if (dport >= 0)
1552145510Sdarrenr			sprintf(str2, "%s,%d", getip(ver, &daddr), dport);
1553145510Sdarrenr		else
1554145510Sdarrenr			sprintf(str2, "%s", getip(ver, &daddr));
1555145510Sdarrenr
1556145510Sdarrenr		if (protocol < 0)
1557145510Sdarrenr			strcpy(str3, "any");
1558145510Sdarrenr		else if ((proto = getprotobynumber(protocol)) != NULL)
1559145510Sdarrenr			sprintf(str3, "%s", proto->p_name);
1560145510Sdarrenr		else
1561145510Sdarrenr			sprintf(str3, "%d", protocol);
1562145510Sdarrenr
1563145510Sdarrenr		switch (sorting)
1564145510Sdarrenr		{
1565145510Sdarrenr		case STSORT_PR:
1566145510Sdarrenr			sprintf(str4, "proto");
1567145510Sdarrenr			break;
1568145510Sdarrenr		case STSORT_PKTS:
1569145510Sdarrenr			sprintf(str4, "# pkts");
1570145510Sdarrenr			break;
1571145510Sdarrenr		case STSORT_BYTES:
1572145510Sdarrenr			sprintf(str4, "# bytes");
1573145510Sdarrenr			break;
1574145510Sdarrenr		case STSORT_TTL:
1575145510Sdarrenr			sprintf(str4, "ttl");
1576145510Sdarrenr			break;
1577145510Sdarrenr		case STSORT_SRCIP:
1578145510Sdarrenr			sprintf(str4, "src ip");
1579145510Sdarrenr			break;
1580145510Sdarrenr		case STSORT_SRCPT:
1581145510Sdarrenr			sprintf(str4, "src port");
1582145510Sdarrenr			break;
1583145510Sdarrenr		case STSORT_DSTIP:
1584145510Sdarrenr			sprintf(str4, "dest ip");
1585145510Sdarrenr			break;
1586145510Sdarrenr		case STSORT_DSTPT:
1587145510Sdarrenr			sprintf(str4, "dest port");
1588145510Sdarrenr			break;
1589145510Sdarrenr		default:
1590145510Sdarrenr			sprintf(str4, "unknown");
1591145510Sdarrenr			break;
1592145510Sdarrenr		}
1593145510Sdarrenr
1594145510Sdarrenr		if (reverse)
1595145510Sdarrenr			strcat(str4, " (reverse)");
1596145510Sdarrenr
1597145510Sdarrenr		winy += 2;
1598145510Sdarrenr		move(winy,0);
1599145510Sdarrenr		printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
1600145510Sdarrenr		       str1, str2, str3, str4);
1601145510Sdarrenr
1602255332Scy		/*
1603145510Sdarrenr		 * For an IPv4 IP address we need at most 15 characters,
1604145510Sdarrenr		 * 4 tuples of 3 digits, separated by 3 dots. Enforce this
1605145510Sdarrenr		 * length, so the colums do not change positions based
1606145510Sdarrenr		 * on the size of the IP address. This length makes the
1607255332Scy		 * output fit in a 80 column terminal.
1608145510Sdarrenr		 * We are lacking a good solution for IPv6 addresses (that
1609255332Scy		 * can be longer that 15 characters), so we do not enforce
1610145510Sdarrenr		 * a maximum on the IP field size.
1611145510Sdarrenr		 */
1612145510Sdarrenr		if (srclen < 15)
1613145510Sdarrenr			srclen = 15;
1614145510Sdarrenr		if (dstlen < 15)
1615145510Sdarrenr			dstlen = 15;
1616145510Sdarrenr
1617145510Sdarrenr		/* print column description */
1618145510Sdarrenr		winy += 2;
1619145510Sdarrenr		move(winy,0);
1620145510Sdarrenr		attron(A_BOLD);
1621145510Sdarrenr		printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
1622145510Sdarrenr		       srclen + 6, "Source IP", dstlen + 6, "Destination IP",
1623145510Sdarrenr		       "ST", "PR", "#pkts", "#bytes", "ttl");
1624145510Sdarrenr		attroff(A_BOLD);
1625145510Sdarrenr
1626145510Sdarrenr		/* print all the entries */
1627145510Sdarrenr		tp = tstable;
1628145510Sdarrenr		if (reverse)
1629145510Sdarrenr			tp += tsentry;
1630145510Sdarrenr
1631145510Sdarrenr		if (tsentry > maxy - 6)
1632145510Sdarrenr			tsentry = maxy - 6;
1633145510Sdarrenr		for (i = 0; i <= tsentry; i++) {
1634145510Sdarrenr			/* print src/dest and port */
1635145510Sdarrenr			if ((tp->st_p == IPPROTO_TCP) ||
1636145510Sdarrenr			    (tp->st_p == IPPROTO_UDP)) {
1637145510Sdarrenr				sprintf(str1, "%s,%hu",
1638145510Sdarrenr					getip(tp->st_v, &tp->st_src),
1639145510Sdarrenr					ntohs(tp->st_sport));
1640145510Sdarrenr				sprintf(str2, "%s,%hu",
1641145510Sdarrenr					getip(tp->st_v, &tp->st_dst),
1642145510Sdarrenr					ntohs(tp->st_dport));
1643145510Sdarrenr			} else {
1644145510Sdarrenr				sprintf(str1, "%s", getip(tp->st_v,
1645145510Sdarrenr				    &tp->st_src));
1646145510Sdarrenr				sprintf(str2, "%s", getip(tp->st_v,
1647145510Sdarrenr				    &tp->st_dst));
1648145510Sdarrenr			}
1649145510Sdarrenr			winy++;
1650145510Sdarrenr			move(winy, 0);
1651145510Sdarrenr			printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
1652145510Sdarrenr
1653145510Sdarrenr			/* print state */
1654145510Sdarrenr			sprintf(str1, "%X/%X", tp->st_state[0],
1655145510Sdarrenr				tp->st_state[1]);
1656145510Sdarrenr			printw(" %3s", str1);
1657145510Sdarrenr
1658145510Sdarrenr			/* print protocol */
1659145510Sdarrenr			proto = getprotobynumber(tp->st_p);
1660145510Sdarrenr			if (proto) {
1661145510Sdarrenr				strncpy(str1, proto->p_name, 4);
1662145510Sdarrenr				str1[4] = '\0';
1663145510Sdarrenr			} else {
1664145510Sdarrenr				sprintf(str1, "%d", tp->st_p);
1665145510Sdarrenr			}
1666145510Sdarrenr			/* just print icmp for IPv6-ICMP */
1667145510Sdarrenr			if (tp->st_p == IPPROTO_ICMPV6)
1668145510Sdarrenr				strcpy(str1, "icmp");
1669145510Sdarrenr			printw(" %4s", str1);
1670145510Sdarrenr
1671145510Sdarrenr			/* print #pkt/#bytes */
1672145510Sdarrenr#ifdef	USE_QUAD_T
1673145510Sdarrenr			printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
1674145510Sdarrenr				(unsigned long long) tp->st_bytes);
1675145510Sdarrenr#else
1676145510Sdarrenr			printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
1677145510Sdarrenr#endif
1678145510Sdarrenr			printw(" %9s", ttl_to_string(tp->st_age));
1679145510Sdarrenr
1680145510Sdarrenr			if (reverse)
1681145510Sdarrenr				tp--;
1682145510Sdarrenr			else
1683145510Sdarrenr				tp++;
1684145510Sdarrenr		}
1685145510Sdarrenr
1686145510Sdarrenr		/* screen data structure is filled, now update the screen */
1687145510Sdarrenr		if (redraw)
1688145510Sdarrenr			clearok(stdscr,1);
1689145510Sdarrenr
1690145510Sdarrenr		if (refresh() == ERR)
1691145510Sdarrenr			break;
1692145510Sdarrenr		if (redraw) {
1693145510Sdarrenr			clearok(stdscr,0);
1694145510Sdarrenr			redraw = 0;
1695145510Sdarrenr		}
1696145510Sdarrenr
1697145510Sdarrenr		/* wait for key press or a 1 second time out period */
1698145510Sdarrenr		selecttimeout.tv_sec = refreshtime;
1699145510Sdarrenr		selecttimeout.tv_usec = 0;
1700145510Sdarrenr		FD_ZERO(&readfd);
1701145510Sdarrenr		FD_SET(0, &readfd);
1702145510Sdarrenr		select(1, &readfd, NULL, NULL, &selecttimeout);
1703145510Sdarrenr
1704145510Sdarrenr		/* if key pressed, read all waiting keys */
1705145510Sdarrenr		if (FD_ISSET(0, &readfd)) {
1706145510Sdarrenr			c = wgetch(stdscr);
1707145510Sdarrenr			if (c == ERR)
1708145510Sdarrenr				continue;
1709145510Sdarrenr
1710145510Sdarrenr			if (ISALPHA(c) && ISUPPER(c))
1711145510Sdarrenr				c = TOLOWER(c);
1712145510Sdarrenr			if (c == 'l') {
1713145510Sdarrenr				redraw = 1;
1714145510Sdarrenr			} else if (c == 'q') {
1715145510Sdarrenr				break;
1716145510Sdarrenr			} else if (c == 'r') {
1717145510Sdarrenr				reverse = !reverse;
1718145510Sdarrenr			} else if (c == 'b') {
1719145510Sdarrenr				forward = 0;
1720145510Sdarrenr			} else if (c == 'f') {
1721145510Sdarrenr				forward = 1;
1722145510Sdarrenr			} else if (c == 's') {
1723145510Sdarrenr				if (++sorting > STSORT_MAX)
1724145510Sdarrenr					sorting = 0;
1725145510Sdarrenr			}
1726145510Sdarrenr		}
1727145510Sdarrenr	} /* while */
1728145510Sdarrenr
1729153881Sguidoout:
1730145510Sdarrenr	printw("\n");
1731145510Sdarrenr	curs_set(1);
1732153881Sguido	/* nocbreak(); XXX - endwin() should make this redundant */
1733145510Sdarrenr	endwin();
1734145510Sdarrenr
1735145510Sdarrenr	free(tstable);
1736153881Sguido	if (ret != 0)
1737153881Sguido		perror(errstr);
1738145510Sdarrenr}
1739145510Sdarrenr#endif
1740145510Sdarrenr
1741145510Sdarrenr
1742145510Sdarrenr/*
1743145510Sdarrenr * Show fragment cache information that's held in the kernel.
1744145510Sdarrenr */
1745170268Sdarrenrstatic void showfrstates(ifsp, ticks)
1746255332Scy	ipfrstat_t *ifsp;
1747255332Scy	u_long ticks;
1748145510Sdarrenr{
1749145510Sdarrenr	struct ipfr *ipfrtab[IPFT_SIZE], ifr;
1750145510Sdarrenr	int i;
1751145510Sdarrenr
1752145510Sdarrenr	/*
1753145510Sdarrenr	 * print out the numeric statistics
1754145510Sdarrenr	 */
1755255332Scy	PRINTF("IP fragment states:\n%lu\tnew\n%lu\texpired\n%lu\thits\n",
1756145510Sdarrenr		ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
1757255332Scy	PRINTF("%lu\tretrans\n%lu\ttoo short\n",
1758145510Sdarrenr		ifsp->ifs_retrans0, ifsp->ifs_short);
1759255332Scy	PRINTF("%lu\tno memory\n%lu\talready exist\n",
1760145510Sdarrenr		ifsp->ifs_nomem, ifsp->ifs_exists);
1761255332Scy	PRINTF("%lu\tinuse\n", ifsp->ifs_inuse);
1762170268Sdarrenr	PRINTF("\n");
1763145510Sdarrenr
1764170268Sdarrenr	if (live_kernel == 0) {
1765170268Sdarrenr		if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table,
1766170268Sdarrenr			    sizeof(ipfrtab)))
1767170268Sdarrenr			return;
1768170268Sdarrenr	}
1769170268Sdarrenr
1770145510Sdarrenr	/*
1771145510Sdarrenr	 * Print out the contents (if any) of the fragment cache table.
1772145510Sdarrenr	 */
1773170268Sdarrenr	if (live_kernel == 1) {
1774170268Sdarrenr		do {
1775170268Sdarrenr			if (fetchfrag(ipf_fd, IPFGENITER_FRAG, &ifr) != 0)
1776145510Sdarrenr				break;
1777170268Sdarrenr			if (ifr.ipfr_ifp == NULL)
1778170268Sdarrenr				break;
1779170268Sdarrenr			ifr.ipfr_ttl -= ticks;
1780145510Sdarrenr			printfraginfo("", &ifr);
1781255332Scy		} while (ifr.ipfr_next != NULL);
1782170268Sdarrenr	} else {
1783170268Sdarrenr		for (i = 0; i < IPFT_SIZE; i++)
1784170268Sdarrenr			while (ipfrtab[i] != NULL) {
1785170268Sdarrenr				if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1786170268Sdarrenr					    sizeof(ifr)) == -1)
1787170268Sdarrenr					break;
1788170268Sdarrenr				printfraginfo("", &ifr);
1789170268Sdarrenr				ipfrtab[i] = ifr.ipfr_next;
1790170268Sdarrenr			}
1791170268Sdarrenr	}
1792145510Sdarrenr	/*
1793145510Sdarrenr	 * Print out the contents (if any) of the NAT fragment cache table.
1794145510Sdarrenr	 */
1795170268Sdarrenr
1796170268Sdarrenr	if (live_kernel == 0) {
1797170268Sdarrenr		if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,
1798170268Sdarrenr			    sizeof(ipfrtab)))
1799170268Sdarrenr			return;
1800170268Sdarrenr	}
1801170268Sdarrenr
1802170268Sdarrenr	if (live_kernel == 1) {
1803170268Sdarrenr		do {
1804170268Sdarrenr			if (fetchfrag(nat_fd, IPFGENITER_NATFRAG, &ifr) != 0)
1805145510Sdarrenr				break;
1806170268Sdarrenr			if (ifr.ipfr_ifp == NULL)
1807170268Sdarrenr				break;
1808170268Sdarrenr			ifr.ipfr_ttl -= ticks;
1809145510Sdarrenr			printfraginfo("NAT: ", &ifr);
1810255332Scy		} while (ifr.ipfr_next != NULL);
1811170268Sdarrenr	} else {
1812170268Sdarrenr		for (i = 0; i < IPFT_SIZE; i++)
1813170268Sdarrenr			while (ipfrtab[i] != NULL) {
1814170268Sdarrenr				if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1815170268Sdarrenr					    sizeof(ifr)) == -1)
1816170268Sdarrenr					break;
1817170268Sdarrenr				printfraginfo("NAT: ", &ifr);
1818170268Sdarrenr				ipfrtab[i] = ifr.ipfr_next;
1819170268Sdarrenr			}
1820170268Sdarrenr	}
1821145510Sdarrenr}
1822145510Sdarrenr
1823145510Sdarrenr
1824145510Sdarrenr/*
1825145510Sdarrenr * Show stats on how auth within IPFilter has been used
1826145510Sdarrenr */
1827145510Sdarrenrstatic void showauthstates(asp)
1828255332Scy	ipf_authstat_t *asp;
1829145510Sdarrenr{
1830145510Sdarrenr	frauthent_t *frap, fra;
1831170268Sdarrenr	ipfgeniter_t auth;
1832170268Sdarrenr	ipfobj_t obj;
1833145510Sdarrenr
1834170268Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
1835170268Sdarrenr	obj.ipfo_type = IPFOBJ_GENITER;
1836170268Sdarrenr	obj.ipfo_size = sizeof(auth);
1837170268Sdarrenr	obj.ipfo_ptr = &auth;
1838170268Sdarrenr
1839170268Sdarrenr	auth.igi_type = IPFGENITER_AUTH;
1840170268Sdarrenr	auth.igi_nitems = 1;
1841170268Sdarrenr	auth.igi_data = &fra;
1842170268Sdarrenr
1843145510Sdarrenr#ifdef	USE_QUAD_T
1844255332Scy	printf("Authorisation hits: %"PRIu64"\tmisses %"PRIu64"\n",
1845145510Sdarrenr		(unsigned long long) asp->fas_hits,
1846145510Sdarrenr		(unsigned long long) asp->fas_miss);
1847145510Sdarrenr#else
1848145510Sdarrenr	printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
1849145510Sdarrenr		asp->fas_miss);
1850145510Sdarrenr#endif
1851145510Sdarrenr	printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
1852145510Sdarrenr		asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
1853145510Sdarrenr		asp->fas_sendok);
1854145510Sdarrenr	printf("queok %ld\nquefail %ld\nexpire %ld\n",
1855145510Sdarrenr		asp->fas_queok, asp->fas_quefail, asp->fas_expire);
1856145510Sdarrenr
1857145510Sdarrenr	frap = asp->fas_faelist;
1858145510Sdarrenr	while (frap) {
1859170268Sdarrenr		if (live_kernel == 1) {
1860170268Sdarrenr			if (ioctl(auth_fd, SIOCGENITER, &obj))
1861170268Sdarrenr				break;
1862170268Sdarrenr		} else {
1863170268Sdarrenr			if (kmemcpy((char *)&fra, (u_long)frap,
1864170268Sdarrenr				    sizeof(fra)) == -1)
1865170268Sdarrenr				break;
1866170268Sdarrenr		}
1867145510Sdarrenr		printf("age %ld\t", fra.fae_age);
1868145510Sdarrenr		printfr(&fra.fae_fr, ioctl);
1869145510Sdarrenr		frap = fra.fae_next;
1870145510Sdarrenr	}
1871145510Sdarrenr}
1872145510Sdarrenr
1873145510Sdarrenr
1874145510Sdarrenr/*
1875145510Sdarrenr * Display groups used for each of filter rules, accounting rules and
1876145510Sdarrenr * authentication, separately.
1877145510Sdarrenr */
1878145510Sdarrenrstatic void showgroups(fiop)
1879255332Scy	struct friostat	*fiop;
1880145510Sdarrenr{
1881145510Sdarrenr	static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
1882145510Sdarrenr	static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH };
1883145510Sdarrenr	frgroup_t *fp, grp;
1884145510Sdarrenr	int on, off, i;
1885145510Sdarrenr
1886145510Sdarrenr	on = fiop->f_active;
1887145510Sdarrenr	off = 1 - on;
1888145510Sdarrenr
1889145510Sdarrenr	for (i = 0; i < 3; i++) {
1890145510Sdarrenr		printf("%s groups (active):\n", gnames[i]);
1891145510Sdarrenr		for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL;
1892145510Sdarrenr		     fp = grp.fg_next)
1893145510Sdarrenr			if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1894145510Sdarrenr				break;
1895145510Sdarrenr			else
1896145510Sdarrenr				printf("%s\n", grp.fg_name);
1897145510Sdarrenr		printf("%s groups (inactive):\n", gnames[i]);
1898145510Sdarrenr		for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL;
1899145510Sdarrenr		     fp = grp.fg_next)
1900145510Sdarrenr			if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1901145510Sdarrenr				break;
1902145510Sdarrenr			else
1903145510Sdarrenr				printf("%s\n", grp.fg_name);
1904145510Sdarrenr	}
1905145510Sdarrenr}
1906145510Sdarrenr
1907255332Scy
1908145510Sdarrenrstatic void parse_ipportstr(argument, ip, port)
1909255332Scy	const char *argument;
1910255332Scy	i6addr_t *ip;
1911255332Scy	int *port;
1912145510Sdarrenr{
1913145510Sdarrenr	char *s, *comma;
1914145510Sdarrenr	int ok = 0;
1915145510Sdarrenr
1916145510Sdarrenr	/* make working copy of argument, Theoretically you must be able
1917145510Sdarrenr	 * to write to optarg, but that seems very ugly to me....
1918145510Sdarrenr	 */
1919145510Sdarrenr	s = strdup(argument);
1920145510Sdarrenr	if (s == NULL)
1921145510Sdarrenr		return;
1922145510Sdarrenr
1923145510Sdarrenr	/* get port */
1924145510Sdarrenr	if ((comma = strchr(s, ',')) != NULL) {
1925145510Sdarrenr		if (!strcasecmp(comma + 1, "any")) {
1926145510Sdarrenr			*port = -1;
1927145510Sdarrenr		} else if (!sscanf(comma + 1, "%d", port) ||
1928145510Sdarrenr			   (*port < 0) || (*port > 65535)) {
1929171017Sdarrenr			fprintf(stderr, "Invalid port specification in %s\n",
1930145510Sdarrenr				argument);
1931145510Sdarrenr			free(s);
1932145510Sdarrenr			exit(-2);
1933145510Sdarrenr		}
1934145510Sdarrenr		*comma = '\0';
1935145510Sdarrenr	}
1936145510Sdarrenr
1937145510Sdarrenr
1938145510Sdarrenr	/* get ip address */
1939145510Sdarrenr	if (!strcasecmp(s, "any")) {
1940145510Sdarrenr		ip->in4.s_addr = INADDR_ANY;
1941171017Sdarrenr		ok = 1;
1942145510Sdarrenr#ifdef	USE_INET6
1943145510Sdarrenr		ip->in6 = in6addr_any;
1944145510Sdarrenr	} else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) {
1945145510Sdarrenr		ok = 1;
1946145510Sdarrenr#endif
1947145510Sdarrenr	} else if (inet_aton(s, &ip->in4))
1948145510Sdarrenr		ok = 1;
1949145510Sdarrenr
1950145510Sdarrenr	if (ok == 0) {
1951145510Sdarrenr		fprintf(stderr, "Invalid IP address: %s\n", s);
1952145510Sdarrenr		free(s);
1953145510Sdarrenr		exit(-2);
1954145510Sdarrenr	}
1955145510Sdarrenr
1956145510Sdarrenr	/* free allocated memory */
1957145510Sdarrenr	free(s);
1958145510Sdarrenr}
1959145510Sdarrenr
1960145510Sdarrenr
1961145510Sdarrenr#ifdef STATETOP
1962145510Sdarrenrstatic void sig_resize(s)
1963255332Scy	int s;
1964145510Sdarrenr{
1965145510Sdarrenr	handle_resize = 1;
1966145510Sdarrenr}
1967145510Sdarrenr
1968145510Sdarrenrstatic void sig_break(s)
1969255332Scy	int s;
1970145510Sdarrenr{
1971145510Sdarrenr	handle_break = 1;
1972145510Sdarrenr}
1973145510Sdarrenr
1974145510Sdarrenrstatic char *getip(v, addr)
1975255332Scy	int v;
1976255332Scy	i6addr_t *addr;
1977145510Sdarrenr{
1978153881Sguido#ifdef  USE_INET6
1979145510Sdarrenr	static char hostbuf[MAXHOSTNAMELEN+1];
1980153881Sguido#endif
1981145510Sdarrenr
1982145510Sdarrenr	if (v == 4)
1983145510Sdarrenr		return inet_ntoa(addr->in4);
1984145510Sdarrenr
1985145510Sdarrenr#ifdef  USE_INET6
1986145510Sdarrenr	(void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1);
1987145510Sdarrenr	hostbuf[MAXHOSTNAMELEN] = '\0';
1988145510Sdarrenr	return hostbuf;
1989145510Sdarrenr#else
1990145510Sdarrenr	return "IPv6";
1991145510Sdarrenr#endif
1992145510Sdarrenr}
1993145510Sdarrenr
1994145510Sdarrenr
1995145510Sdarrenrstatic char *ttl_to_string(ttl)
1996255332Scy	long int ttl;
1997145510Sdarrenr{
1998145510Sdarrenr	static char ttlbuf[STSTRSIZE];
1999145510Sdarrenr	int hours, minutes, seconds;
2000145510Sdarrenr
2001145510Sdarrenr	/* ttl is in half seconds */
2002145510Sdarrenr	ttl /= 2;
2003145510Sdarrenr
2004145510Sdarrenr	hours = ttl / 3600;
2005145510Sdarrenr	ttl = ttl % 3600;
2006145510Sdarrenr	minutes = ttl / 60;
2007145510Sdarrenr	seconds = ttl % 60;
2008145510Sdarrenr
2009145510Sdarrenr	if (hours > 0)
2010145510Sdarrenr		sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds);
2011145510Sdarrenr	else
2012145510Sdarrenr		sprintf(ttlbuf, "%2d:%02d", minutes, seconds);
2013145510Sdarrenr	return ttlbuf;
2014145510Sdarrenr}
2015145510Sdarrenr
2016145510Sdarrenr
2017145510Sdarrenrstatic int sort_pkts(a, b)
2018255332Scy	const void *a;
2019255332Scy	const void *b;
2020145510Sdarrenr{
2021145510Sdarrenr
2022145510Sdarrenr	register const statetop_t *ap = a;
2023145510Sdarrenr	register const statetop_t *bp = b;
2024145510Sdarrenr
2025145510Sdarrenr	if (ap->st_pkts == bp->st_pkts)
2026145510Sdarrenr		return 0;
2027145510Sdarrenr	else if (ap->st_pkts < bp->st_pkts)
2028145510Sdarrenr		return 1;
2029145510Sdarrenr	return -1;
2030145510Sdarrenr}
2031145510Sdarrenr
2032145510Sdarrenr
2033145510Sdarrenrstatic int sort_bytes(a, b)
2034255332Scy	const void *a;
2035255332Scy	const void *b;
2036145510Sdarrenr{
2037145510Sdarrenr	register const statetop_t *ap = a;
2038145510Sdarrenr	register const statetop_t *bp = b;
2039145510Sdarrenr
2040145510Sdarrenr	if (ap->st_bytes == bp->st_bytes)
2041145510Sdarrenr		return 0;
2042145510Sdarrenr	else if (ap->st_bytes < bp->st_bytes)
2043145510Sdarrenr		return 1;
2044145510Sdarrenr	return -1;
2045145510Sdarrenr}
2046145510Sdarrenr
2047145510Sdarrenr
2048145510Sdarrenrstatic int sort_p(a, b)
2049255332Scy	const void *a;
2050255332Scy	const void *b;
2051145510Sdarrenr{
2052145510Sdarrenr	register const statetop_t *ap = a;
2053145510Sdarrenr	register const statetop_t *bp = b;
2054145510Sdarrenr
2055145510Sdarrenr	if (ap->st_p == bp->st_p)
2056145510Sdarrenr		return 0;
2057145510Sdarrenr	else if (ap->st_p < bp->st_p)
2058145510Sdarrenr		return 1;
2059145510Sdarrenr	return -1;
2060145510Sdarrenr}
2061145510Sdarrenr
2062145510Sdarrenr
2063145510Sdarrenrstatic int sort_ttl(a, b)
2064255332Scy	const void *a;
2065255332Scy	const void *b;
2066145510Sdarrenr{
2067145510Sdarrenr	register const statetop_t *ap = a;
2068145510Sdarrenr	register const statetop_t *bp = b;
2069145510Sdarrenr
2070145510Sdarrenr	if (ap->st_age == bp->st_age)
2071145510Sdarrenr		return 0;
2072145510Sdarrenr	else if (ap->st_age < bp->st_age)
2073145510Sdarrenr		return 1;
2074145510Sdarrenr	return -1;
2075145510Sdarrenr}
2076145510Sdarrenr
2077145510Sdarrenrstatic int sort_srcip(a, b)
2078255332Scy	const void *a;
2079255332Scy	const void *b;
2080145510Sdarrenr{
2081145510Sdarrenr	register const statetop_t *ap = a;
2082145510Sdarrenr	register const statetop_t *bp = b;
2083145510Sdarrenr
2084145510Sdarrenr#ifdef USE_INET6
2085145510Sdarrenr	if (use_inet6) {
2086145510Sdarrenr		if (IP6_EQ(&ap->st_src, &bp->st_src))
2087145510Sdarrenr			return 0;
2088145510Sdarrenr		else if (IP6_GT(&ap->st_src, &bp->st_src))
2089145510Sdarrenr			return 1;
2090145510Sdarrenr	} else
2091145510Sdarrenr#endif
2092145510Sdarrenr	{
2093145510Sdarrenr		if (ntohl(ap->st_src.in4.s_addr) ==
2094145510Sdarrenr		    ntohl(bp->st_src.in4.s_addr))
2095145510Sdarrenr			return 0;
2096145510Sdarrenr		else if (ntohl(ap->st_src.in4.s_addr) >
2097145510Sdarrenr		         ntohl(bp->st_src.in4.s_addr))
2098145510Sdarrenr			return 1;
2099145510Sdarrenr	}
2100145510Sdarrenr	return -1;
2101145510Sdarrenr}
2102145510Sdarrenr
2103145510Sdarrenrstatic int sort_srcpt(a, b)
2104255332Scy	const void *a;
2105255332Scy	const void *b;
2106145510Sdarrenr{
2107145510Sdarrenr	register const statetop_t *ap = a;
2108145510Sdarrenr	register const statetop_t *bp = b;
2109145510Sdarrenr
2110145510Sdarrenr	if (htons(ap->st_sport) == htons(bp->st_sport))
2111145510Sdarrenr		return 0;
2112145510Sdarrenr	else if (htons(ap->st_sport) > htons(bp->st_sport))
2113145510Sdarrenr		return 1;
2114145510Sdarrenr	return -1;
2115145510Sdarrenr}
2116145510Sdarrenr
2117145510Sdarrenrstatic int sort_dstip(a, b)
2118255332Scy	const void *a;
2119255332Scy	const void *b;
2120145510Sdarrenr{
2121145510Sdarrenr	register const statetop_t *ap = a;
2122145510Sdarrenr	register const statetop_t *bp = b;
2123145510Sdarrenr
2124145510Sdarrenr#ifdef USE_INET6
2125145510Sdarrenr	if (use_inet6) {
2126145510Sdarrenr		if (IP6_EQ(&ap->st_dst, &bp->st_dst))
2127145510Sdarrenr			return 0;
2128145510Sdarrenr		else if (IP6_GT(&ap->st_dst, &bp->st_dst))
2129145510Sdarrenr			return 1;
2130145510Sdarrenr	} else
2131145510Sdarrenr#endif
2132145510Sdarrenr	{
2133145510Sdarrenr		if (ntohl(ap->st_dst.in4.s_addr) ==
2134145510Sdarrenr		    ntohl(bp->st_dst.in4.s_addr))
2135145510Sdarrenr			return 0;
2136145510Sdarrenr		else if (ntohl(ap->st_dst.in4.s_addr) >
2137145510Sdarrenr		         ntohl(bp->st_dst.in4.s_addr))
2138145510Sdarrenr			return 1;
2139145510Sdarrenr	}
2140145510Sdarrenr	return -1;
2141145510Sdarrenr}
2142145510Sdarrenr
2143145510Sdarrenrstatic int sort_dstpt(a, b)
2144255332Scy	const void *a;
2145255332Scy	const void *b;
2146145510Sdarrenr{
2147145510Sdarrenr	register const statetop_t *ap = a;
2148145510Sdarrenr	register const statetop_t *bp = b;
2149145510Sdarrenr
2150145510Sdarrenr	if (htons(ap->st_dport) == htons(bp->st_dport))
2151145510Sdarrenr		return 0;
2152145510Sdarrenr	else if (htons(ap->st_dport) > htons(bp->st_dport))
2153145510Sdarrenr		return 1;
2154145510Sdarrenr	return -1;
2155145510Sdarrenr}
2156145510Sdarrenr
2157145510Sdarrenr#endif
2158170268Sdarrenr
2159170268Sdarrenr
2160170268Sdarrenripstate_t *fetchstate(src, dst)
2161255332Scy	ipstate_t *src, *dst;
2162170268Sdarrenr{
2163170268Sdarrenr
2164170268Sdarrenr	if (live_kernel == 1) {
2165170268Sdarrenr		ipfgeniter_t state;
2166170268Sdarrenr		ipfobj_t obj;
2167170268Sdarrenr
2168170268Sdarrenr		obj.ipfo_rev = IPFILTER_VERSION;
2169170268Sdarrenr		obj.ipfo_type = IPFOBJ_GENITER;
2170170268Sdarrenr		obj.ipfo_size = sizeof(state);
2171170268Sdarrenr		obj.ipfo_ptr = &state;
2172170268Sdarrenr
2173170268Sdarrenr		state.igi_type = IPFGENITER_STATE;
2174170268Sdarrenr		state.igi_nitems = 1;
2175170268Sdarrenr		state.igi_data = dst;
2176170268Sdarrenr
2177170268Sdarrenr		if (ioctl(state_fd, SIOCGENITER, &obj) != 0)
2178170268Sdarrenr			return NULL;
2179170268Sdarrenr		if (dst->is_next == NULL) {
2180255332Scy			int n = IPFGENITER_STATE;
2181255332Scy			(void) ioctl(ipf_fd,SIOCIPFDELTOK, &n);
2182170268Sdarrenr		}
2183170268Sdarrenr	} else {
2184170268Sdarrenr		if (kmemcpy((char *)dst, (u_long)src, sizeof(*dst)))
2185170268Sdarrenr			return NULL;
2186170268Sdarrenr	}
2187170268Sdarrenr	return dst;
2188170268Sdarrenr}
2189170268Sdarrenr
2190170268Sdarrenr
2191170268Sdarrenrstatic int fetchfrag(fd, type, frp)
2192255332Scy	int fd, type;
2193255332Scy	ipfr_t *frp;
2194170268Sdarrenr{
2195170268Sdarrenr	ipfgeniter_t frag;
2196170268Sdarrenr	ipfobj_t obj;
2197170268Sdarrenr
2198170268Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
2199170268Sdarrenr	obj.ipfo_type = IPFOBJ_GENITER;
2200170268Sdarrenr	obj.ipfo_size = sizeof(frag);
2201170268Sdarrenr	obj.ipfo_ptr = &frag;
2202170268Sdarrenr
2203170268Sdarrenr	frag.igi_type = type;
2204170268Sdarrenr	frag.igi_nitems = 1;
2205170268Sdarrenr	frag.igi_data = frp;
2206170268Sdarrenr
2207170268Sdarrenr	if (ioctl(fd, SIOCGENITER, &obj))
2208170268Sdarrenr		return EFAULT;
2209170268Sdarrenr	return 0;
2210170268Sdarrenr}
2211170268Sdarrenr
2212170268Sdarrenr
2213255332Scystatic int state_matcharray(stp, array)
2214255332Scy	ipstate_t *stp;
2215255332Scy	int *array;
2216255332Scy{
2217255332Scy	int i, n, *x, rv, p;
2218255332Scy	ipfexp_t *e;
2219255332Scy
2220255332Scy	rv = 0;
2221255332Scy
2222255332Scy	for (n = array[0], x = array + 1; n > 0; x += e->ipfe_size) {
2223255332Scy		e = (ipfexp_t *)x;
2224255332Scy		if (e->ipfe_cmd == IPF_EXP_END)
2225255332Scy			break;
2226255332Scy		n -= e->ipfe_size;
2227255332Scy
2228255332Scy		rv = 0;
2229255332Scy		/*
2230255332Scy		 * The upper 16 bits currently store the protocol value.
2231255332Scy		 * This is currently used with TCP and UDP port compares and
2232255332Scy		 * allows "tcp.port = 80" without requiring an explicit
2233255332Scy		 " "ip.pr = tcp" first.
2234255332Scy		 */
2235255332Scy		p = e->ipfe_cmd >> 16;
2236255332Scy		if ((p != 0) && (p != stp->is_p))
2237255332Scy			break;
2238255332Scy
2239255332Scy		switch (e->ipfe_cmd)
2240255332Scy		{
2241255332Scy		case IPF_EXP_IP_PR :
2242255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2243255332Scy				rv |= (stp->is_p == e->ipfe_arg0[i]);
2244255332Scy			}
2245255332Scy			break;
2246255332Scy
2247255332Scy		case IPF_EXP_IP_SRCADDR :
2248255332Scy			if (stp->is_v != 4)
2249255332Scy				break;
2250255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2251255332Scy				rv |= ((stp->is_saddr &
2252255332Scy					e->ipfe_arg0[i * 2 + 1]) ==
2253255332Scy				       e->ipfe_arg0[i * 2]);
2254255332Scy			}
2255255332Scy			break;
2256255332Scy
2257255332Scy		case IPF_EXP_IP_DSTADDR :
2258255332Scy			if (stp->is_v != 4)
2259255332Scy				break;
2260255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2261255332Scy				rv |= ((stp->is_daddr &
2262255332Scy					e->ipfe_arg0[i * 2 + 1]) ==
2263255332Scy				       e->ipfe_arg0[i * 2]);
2264255332Scy			}
2265255332Scy			break;
2266255332Scy
2267255332Scy		case IPF_EXP_IP_ADDR :
2268255332Scy			if (stp->is_v != 4)
2269255332Scy				break;
2270255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2271255332Scy				rv |= ((stp->is_saddr &
2272255332Scy					e->ipfe_arg0[i * 2 + 1]) ==
2273255332Scy				       e->ipfe_arg0[i * 2]) ||
2274255332Scy				      ((stp->is_daddr &
2275255332Scy					e->ipfe_arg0[i * 2 + 1]) ==
2276255332Scy				       e->ipfe_arg0[i * 2]);
2277255332Scy			}
2278255332Scy			break;
2279255332Scy
2280255332Scy#ifdef USE_INET6
2281255332Scy		case IPF_EXP_IP6_SRCADDR :
2282255332Scy			if (stp->is_v != 6)
2283255332Scy				break;
2284255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2285255332Scy				rv |= IP6_MASKEQ(&stp->is_src,
2286255332Scy						 &e->ipfe_arg0[i * 8 + 4],
2287255332Scy						 &e->ipfe_arg0[i * 8]);
2288255332Scy			}
2289255332Scy			break;
2290255332Scy
2291255332Scy		case IPF_EXP_IP6_DSTADDR :
2292255332Scy			if (stp->is_v != 6)
2293255332Scy				break;
2294255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2295255332Scy				rv |= IP6_MASKEQ(&stp->is_dst,
2296255332Scy						 &e->ipfe_arg0[i * 8 + 4],
2297255332Scy						 &e->ipfe_arg0[i * 8]);
2298255332Scy			}
2299255332Scy			break;
2300255332Scy
2301255332Scy		case IPF_EXP_IP6_ADDR :
2302255332Scy			if (stp->is_v != 6)
2303255332Scy				break;
2304255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2305255332Scy				rv |= IP6_MASKEQ(&stp->is_src,
2306255332Scy						 &e->ipfe_arg0[i * 8 + 4],
2307255332Scy						 &e->ipfe_arg0[i * 8]) ||
2308255332Scy				      IP6_MASKEQ(&stp->is_dst,
2309255332Scy						 &e->ipfe_arg0[i * 8 + 4],
2310255332Scy						 &e->ipfe_arg0[i * 8]);
2311255332Scy			}
2312255332Scy			break;
2313255332Scy#endif
2314255332Scy
2315255332Scy		case IPF_EXP_UDP_PORT :
2316255332Scy		case IPF_EXP_TCP_PORT :
2317255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2318255332Scy				rv |= (stp->is_sport == e->ipfe_arg0[i]) ||
2319255332Scy				      (stp->is_dport == e->ipfe_arg0[i]);
2320255332Scy			}
2321255332Scy			break;
2322255332Scy
2323255332Scy		case IPF_EXP_UDP_SPORT :
2324255332Scy		case IPF_EXP_TCP_SPORT :
2325255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2326255332Scy				rv |= (stp->is_sport == e->ipfe_arg0[i]);
2327255332Scy			}
2328255332Scy			break;
2329255332Scy
2330255332Scy		case IPF_EXP_UDP_DPORT :
2331255332Scy		case IPF_EXP_TCP_DPORT :
2332255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2333255332Scy				rv |= (stp->is_dport == e->ipfe_arg0[i]);
2334255332Scy			}
2335255332Scy			break;
2336255332Scy
2337255332Scy		case IPF_EXP_IDLE_GT :
2338255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2339255332Scy				rv |= (stp->is_die < e->ipfe_arg0[i]);
2340255332Scy			}
2341255332Scy			break;
2342255332Scy
2343255332Scy		case IPF_EXP_TCP_STATE :
2344255332Scy			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2345255332Scy				rv |= (stp->is_state[0] == e->ipfe_arg0[i]) ||
2346255332Scy				      (stp->is_state[1] == e->ipfe_arg0[i]);
2347255332Scy			}
2348255332Scy			break;
2349255332Scy		}
2350255332Scy		rv ^= e->ipfe_not;
2351255332Scy
2352255332Scy		if (rv == 0)
2353255332Scy			break;
2354255332Scy	}
2355255332Scy
2356255332Scy	return rv;
2357255332Scy}
2358255332Scy
2359255332Scy
2360170268Sdarrenrstatic void showtqtable_live(fd)
2361255332Scy	int fd;
2362170268Sdarrenr{
2363170268Sdarrenr	ipftq_t table[IPF_TCP_NSTATES];
2364170268Sdarrenr	ipfobj_t obj;
2365170268Sdarrenr
2366170268Sdarrenr	bzero((char *)&obj, sizeof(obj));
2367170268Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
2368170268Sdarrenr	obj.ipfo_size = sizeof(table);
2369170268Sdarrenr	obj.ipfo_ptr = (void *)table;
2370170268Sdarrenr	obj.ipfo_type = IPFOBJ_STATETQTAB;
2371170268Sdarrenr
2372170268Sdarrenr	if (ioctl(fd, SIOCGTQTAB, &obj) == 0) {
2373170268Sdarrenr		printtqtable(table);
2374170268Sdarrenr	}
2375170268Sdarrenr}
2376