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