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