xref: /netbsd-src/external/bsd/ipf/dist/tools/ipfstat.c (revision 07967fb18af5b87d2d477c5b3e1e438bf0c293fb)
1 /*	$NetBSD: ipfstat.c,v 1.6 2018/02/04 08:19:42 mrg Exp $	*/
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 __attribute__((__used__)) const char sccsid[] = "@(#)fils.c	1.21 4/20/96 (C) 1993-2000 Darren Reed";
75 static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ipfstat.c,v 1.1.1.2 2012/07/22 13:44:55 darrenr";
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 	ipfobj_t obj;
803 	void *buf;
804 	size_t bufsiz;
805 	int rules;
806 	int num;
807 
808 	rules = 0;
809 
810 	rule.iri_inout = out;
811 	rule.iri_active = set;
812 	rule.iri_rule = &fb;
813 	rule.iri_nrules = 1;
814 	if (group != NULL)
815 		strncpy(rule.iri_group, group, FR_GROUPLEN);
816 	else
817 		rule.iri_group[0] = '\0';
818 
819 	bzero((char *)&zero, sizeof(zero));
820 
821 	bzero((char *)&obj, sizeof(obj));
822 	obj.ipfo_rev = IPFILTER_VERSION;
823 	obj.ipfo_type = IPFOBJ_IPFITER;
824 	obj.ipfo_size = sizeof(rule);
825 	obj.ipfo_ptr = &rule;
826 
827 	/*
828 	 * The API does not know how much we need for filter data. Assume
829 	 * 10K is large enough. XXX: The code silently fails elsewhere on
830 	 * allocation, we do the same here.
831 	 */
832 	if ((buf = malloc(bufsiz = sizeof(*fp) + 10240)) == NULL)
833 		return 0;
834 
835 	while (rule.iri_rule != NULL) {
836 		memset(buf, 0xff, bufsiz);
837 		fp = buf;
838 		rule.iri_rule = fp;
839 		if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) {
840 			ipferror(ipf_fd, "ioctl(SIOCIPFITER)");
841 			num = IPFGENITER_IPF;
842 			(void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
843 			return rules;
844 		}
845 		if (bcmp(fp, &zero, sizeof(zero)) == 0)
846 			break;
847 		if (rule.iri_rule == NULL)
848 			break;
849 #ifdef USE_INET6
850 		if (use_inet6 != 0) {
851 			if (fp->fr_family != 0 && fp->fr_family != AF_INET6)
852 				continue;
853 		} else
854 #endif
855 		{
856 			if (fp->fr_family != 0 && fp->fr_family != AF_INET)
857 				continue;
858 		}
859 		if (fp->fr_data != NULL) {
860 			fp->fr_data = calloc(1, fp->fr_dsize);
861 			if (fp->fr_data != NULL) {
862 				memcpy(fp->fr_data, (char *)fp + fp->fr_size,
863 				    fp->fr_dsize);
864 			}
865 		}
866 
867 		rules++;
868 
869 		if (opts & (OPT_HITS|OPT_DEBUG))
870 #ifdef	USE_QUAD_T
871 			PRINTF("%llu ", (unsigned long long) fp->fr_hits);
872 #else
873 			PRINTF("%lu ", fp->fr_hits);
874 #endif
875 		if (opts & (OPT_ACCNT|OPT_DEBUG))
876 #ifdef	USE_QUAD_T
877 			PRINTF("%llu ", (unsigned long long) fp->fr_bytes);
878 #else
879 			PRINTF("%lu ", fp->fr_bytes);
880 #endif
881 		if (opts & OPT_SHOWLINENO)
882 			PRINTF("@%d ", rules);
883 
884 		if (fp->fr_die != 0)
885 			fp->fr_die -= fiop->f_ticks;
886 
887 		printfr(fp, ioctl);
888 		if (opts & OPT_DEBUG) {
889 			binprint(fp, fp->fr_size);
890 			if (fp->fr_data != NULL && fp->fr_dsize > 0)
891 				binprint(fp->fr_data, fp->fr_dsize);
892 		}
893 		if (fp->fr_type == FR_T_CALLFUNC) {
894 			rules += printlivelist(fiop, out, set, fp->fr_data,
895 					       group, "# callfunc: ");
896 		}
897 	}
898 
899 	num = IPFGENITER_IPF;
900 	(void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
901 
902 	return rules;
903 }
904 
905 
printdeadlist(fiop,out,set,fp,group,comment)906 static void printdeadlist(fiop, out, set, fp, group, comment)
907 	friostat_t *fiop;
908 	int out, set;
909 	frentry_t *fp;
910 	char *group, *comment;
911 {
912 	frgroup_t *grtop, *grtail, *g;
913 	struct	frentry	fb;
914 	char	*data;
915 	u_32_t	type;
916 	int	n;
917 
918 	fb.fr_next = fp;
919 	n = 0;
920 	grtop = NULL;
921 	grtail = NULL;
922 
923 	for (n = 1; fp; fp = fb.fr_next, n++) {
924 		if (kmemcpy((char *)&fb, (u_long)fb.fr_next,
925 			    fb.fr_size) == -1) {
926 			perror("kmemcpy");
927 			return;
928 		}
929 		fp = &fb;
930 		if (use_inet6 != 0) {
931 			if (fp->fr_family != 0 && fp->fr_family != 6)
932 				continue;
933 		} else {
934 			if (fp->fr_family != 0 && fp->fr_family != 4)
935 				continue;
936 		}
937 
938 		data = NULL;
939 		type = fb.fr_type & ~FR_T_BUILTIN;
940 		if (type == FR_T_IPF || type == FR_T_BPFOPC) {
941 			if (fb.fr_dsize) {
942 				data = malloc(fb.fr_dsize);
943 
944 				if (kmemcpy(data, (u_long)fb.fr_data,
945 					    fb.fr_dsize) == -1) {
946 					perror("kmemcpy");
947 					return;
948 				}
949 				fb.fr_data = data;
950 			}
951 		}
952 
953 		if (opts & OPT_HITS)
954 #ifdef	USE_QUAD_T
955 			PRINTF("%llu ", (unsigned long long) fb.fr_hits);
956 #else
957 			PRINTF("%lu ", fb.fr_hits);
958 #endif
959 		if (opts & OPT_ACCNT)
960 #ifdef	USE_QUAD_T
961 			PRINTF("%llu ", (unsigned long long) fb.fr_bytes);
962 #else
963 			PRINTF("%lu ", fb.fr_bytes);
964 #endif
965 		if (opts & OPT_SHOWLINENO)
966 			PRINTF("@%d ", n);
967 
968 		printfr(fp, ioctl);
969 		if (opts & OPT_DEBUG) {
970 			binprint(fp, fp->fr_size);
971 			if (fb.fr_data != NULL && fb.fr_dsize > 0)
972 				binprint(fb.fr_data, fb.fr_dsize);
973 		}
974 		if (data != NULL)
975 			free(data);
976 		if (fb.fr_grhead != -1) {
977 			g = calloc(1, sizeof(*g));
978 
979 			if (g != NULL) {
980 				strncpy(g->fg_name, fb.fr_names + fb.fr_grhead,
981 					FR_GROUPLEN);
982 				if (grtop == NULL) {
983 					grtop = g;
984 					grtail = g;
985 				} else {
986 					grtail->fg_next = g;
987 					grtail = g;
988 				}
989 			}
990 		}
991 		if (type == FR_T_CALLFUNC) {
992 			printdeadlist(fiop, out, set, fb.fr_data, group,
993 				      "# callfunc: ");
994 		}
995 	}
996 
997 	while ((g = grtop) != NULL) {
998 		printdeadlist(fiop, out, set, NULL, g->fg_name, comment);
999 		grtop = g->fg_next;
1000 		free(g);
1001 	}
1002 }
1003 
1004 /*
1005  * print out all of the asked for rule sets, using the stats struct as
1006  * the base from which to get the pointers.
1007  */
showlist(fiop)1008 static	void	showlist(fiop)
1009 	struct	friostat	*fiop;
1010 {
1011 	struct	frentry	*fp = NULL;
1012 	int	i, set;
1013 
1014 	set = fiop->f_active;
1015 	if (opts & OPT_INACTIVE)
1016 		set = 1 - set;
1017 	if (opts & OPT_ACCNT) {
1018 		if (opts & OPT_OUTQUE) {
1019 			i = F_ACOUT;
1020 			fp = (struct frentry *)fiop->f_acctout[set];
1021 		} else if (opts & OPT_INQUE) {
1022 			i = F_ACIN;
1023 			fp = (struct frentry *)fiop->f_acctin[set];
1024 		} else {
1025 			FPRINTF(stderr, "No -i or -o given with -a\n");
1026 			return;
1027 		}
1028 	} else {
1029 		if (opts & OPT_OUTQUE) {
1030 			i = F_OUT;
1031 			fp = (struct frentry *)fiop->f_fout[set];
1032 		} else if (opts & OPT_INQUE) {
1033 			i = F_IN;
1034 			fp = (struct frentry *)fiop->f_fin[set];
1035 		} else
1036 			return;
1037 	}
1038 	if (opts & OPT_DEBUG)
1039 		FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
1040 
1041 	if (opts & OPT_DEBUG)
1042 		PRINTF("fp %p set %d\n", fp, set);
1043 
1044 	if (live_kernel == 1) {
1045 		int printed;
1046 
1047 		printed = printlivelist(fiop, i, set, fp, NULL, NULL);
1048 		if (printed == 0) {
1049 			FPRINTF(stderr, "# empty list for %s%s\n",
1050 			        (opts & OPT_INACTIVE) ? "inactive " : "",
1051 							filters[i]);
1052 		}
1053 	} else {
1054 		if (!fp) {
1055 			FPRINTF(stderr, "# empty list for %s%s\n",
1056 			        (opts & OPT_INACTIVE) ? "inactive " : "",
1057 							filters[i]);
1058 		} else {
1059 			printdeadlist(fiop, i, set, fp, NULL, NULL);
1060 		}
1061 	}
1062 }
1063 
1064 
1065 /*
1066  * Display ipfilter stateful filtering information
1067  */
showipstates(ipsp,filter)1068 static void showipstates(ipsp, filter)
1069 	ips_stat_t *ipsp;
1070 	int *filter;
1071 {
1072 	ipstate_t *is;
1073 	int i;
1074 
1075 	/*
1076 	 * If a list of states hasn't been asked for, only print out stats
1077 	 */
1078 	if (!(opts & OPT_SHOWLIST)) {
1079 		showstatestats(ipsp);
1080 		return;
1081 	}
1082 
1083 	if ((state_fields != NULL) && (nohdrfields == 0)) {
1084 		for (i = 0; state_fields[i].w_value != 0; i++) {
1085 			printfieldhdr(statefields, state_fields + i);
1086 			if (state_fields[i + 1].w_value != 0)
1087 				printf("\t");
1088 		}
1089 		printf("\n");
1090 	}
1091 
1092 	/*
1093 	 * Print out all the state information currently held in the kernel.
1094 	 */
1095 	for (is = ipsp->iss_list; is != NULL; ) {
1096 		ipstate_t ips;
1097 
1098 		is = fetchstate(is, &ips);
1099 
1100 		if (is == NULL)
1101 			break;
1102 
1103 		is = ips.is_next;
1104 		if ((filter != NULL) &&
1105 		    (state_matcharray(&ips, filter) == 0)) {
1106 			continue;
1107 		}
1108 		if (state_fields != NULL) {
1109 			for (i = 0; state_fields[i].w_value != 0; i++) {
1110 				printstatefield(&ips, state_fields[i].w_value);
1111 				if (state_fields[i + 1].w_value != 0)
1112 					printf("\t");
1113 			}
1114 			printf("\n");
1115 		} else {
1116 			printstate(&ips, opts, ipsp->iss_ticks);
1117 		}
1118 	}
1119 }
1120 
1121 
showstatestats(ipsp)1122 static void showstatestats(ipsp)
1123 	ips_stat_t *ipsp;
1124 {
1125 	int minlen, maxlen, totallen;
1126 	ipftable_t table;
1127 	u_int *buckets;
1128 	ipfobj_t obj;
1129 	int i, sz;
1130 
1131 	/*
1132 	 * If a list of states hasn't been asked for, only print out stats
1133 	 */
1134 
1135 	sz = sizeof(*buckets) * ipsp->iss_state_size;
1136 	buckets = (u_int *)malloc(sz);
1137 
1138 	obj.ipfo_rev = IPFILTER_VERSION;
1139 	obj.ipfo_type = IPFOBJ_GTABLE;
1140 	obj.ipfo_size = sizeof(table);
1141 	obj.ipfo_ptr = &table;
1142 
1143 	table.ita_type = IPFTABLE_BUCKETS;
1144 	table.ita_table = buckets;
1145 
1146 	if (live_kernel == 1) {
1147 		if (ioctl(state_fd, SIOCGTABL, &obj) != 0) {
1148 			free(buckets);
1149 			return;
1150 		}
1151 	} else {
1152 		if (kmemcpy((char *)buckets,
1153 			    (u_long)ipsp->iss_bucketlen, sz)) {
1154 			free(buckets);
1155 			return;
1156 		}
1157 	}
1158 
1159 	PRINTF("%u\tactive state table entries\n",ipsp->iss_active);
1160 	PRINTF("%lu\tadd bad\n", ipsp->iss_add_bad);
1161 	PRINTF("%lu\tadd duplicate\n", ipsp->iss_add_dup);
1162 	PRINTF("%lu\tadd locked\n", ipsp->iss_add_locked);
1163 	PRINTF("%lu\tadd oow\n", ipsp->iss_add_oow);
1164 	PRINTF("%lu\tbucket full\n", ipsp->iss_bucket_full);
1165 	PRINTF("%lu\tcheck bad\n", ipsp->iss_check_bad);
1166 	PRINTF("%lu\tcheck miss\n", ipsp->iss_check_miss);
1167 	PRINTF("%lu\tcheck nattag\n", ipsp->iss_check_nattag);
1168 	PRINTF("%lu\tclone nomem\n", ipsp->iss_clone_nomem);
1169 	PRINTF("%lu\tcheck notag\n", ipsp->iss_check_notag);
1170 	PRINTF("%lu\tcheck success\n", ipsp->iss_hits);
1171 	PRINTF("%lu\tcloned\n", ipsp->iss_cloned);
1172 	PRINTF("%lu\texpired\n", ipsp->iss_expire);
1173 	PRINTF("%lu\tflush all\n", ipsp->iss_flush_all);
1174 	PRINTF("%lu\tflush closing\n", ipsp->iss_flush_closing);
1175 	PRINTF("%lu\tflush queue\n", ipsp->iss_flush_queue);
1176 	PRINTF("%lu\tflush state\n", ipsp->iss_flush_state);
1177 	PRINTF("%lu\tflush timeout\n", ipsp->iss_flush_timeout);
1178 	PRINTF("%u\thash buckets in use\n", ipsp->iss_inuse);
1179 	PRINTF("%lu\tICMP bad\n", ipsp->iss_icmp_bad);
1180 	PRINTF("%lu\tICMP banned\n", ipsp->iss_icmp_banned);
1181 	PRINTF("%lu\tICMP errors\n", ipsp->iss_icmp_icmperr);
1182 	PRINTF("%lu\tICMP head block\n", ipsp->iss_icmp_headblock);
1183 	PRINTF("%lu\tICMP hits\n", ipsp->iss_icmp_hits);
1184 	PRINTF("%lu\tICMP not query\n",	ipsp->iss_icmp_notquery);
1185 	PRINTF("%lu\tICMP short\n", ipsp->iss_icmp_short);
1186 	PRINTF("%lu\tICMP too many\n", ipsp->iss_icmp_toomany);
1187 	PRINTF("%lu\tICMPv6 errors\n", ipsp->iss_icmp6_icmperr);
1188 	PRINTF("%lu\tICMPv6 miss\n", ipsp->iss_icmp6_miss);
1189 	PRINTF("%lu\tICMPv6 not info\n", ipsp->iss_icmp6_notinfo);
1190 	PRINTF("%lu\tICMPv6 not query\n", ipsp->iss_icmp6_notquery);
1191 	PRINTF("%lu\tlog fail\n", ipsp->iss_log_fail);
1192 	PRINTF("%lu\tlog ok\n", ipsp->iss_log_ok);
1193 	PRINTF("%lu\tlookup interface mismatch\n", ipsp->iss_lookup_badifp);
1194 	PRINTF("%lu\tlookup mask mismatch\n", ipsp->iss_miss_mask);
1195 	PRINTF("%lu\tlookup port mismatch\n", ipsp->iss_lookup_badport);
1196 	PRINTF("%lu\tlookup miss\n", ipsp->iss_lookup_miss);
1197 	PRINTF("%lu\tmaximum rule references\n", ipsp->iss_max_ref);
1198 	PRINTF("%lu\tmaximum hosts per rule\n", ipsp->iss_max_track);
1199 	PRINTF("%lu\tno memory\n", ipsp->iss_nomem);
1200 	PRINTF("%lu\tout of window\n", ipsp->iss_oow);
1201 	PRINTF("%lu\torphans\n", ipsp->iss_orphan);
1202 	PRINTF("%lu\tscan block\n", ipsp->iss_scan_block);
1203 	PRINTF("%lu\tstate table maximum reached\n", ipsp->iss_max);
1204 	PRINTF("%lu\tTCP closing\n", ipsp->iss_tcp_closing);
1205 	PRINTF("%lu\tTCP OOW\n", ipsp->iss_tcp_oow);
1206 	PRINTF("%lu\tTCP RST add\n", ipsp->iss_tcp_rstadd);
1207 	PRINTF("%lu\tTCP too small\n", ipsp->iss_tcp_toosmall);
1208 	PRINTF("%lu\tTCP bad options\n", ipsp->iss_tcp_badopt);
1209 	PRINTF("%lu\tTCP removed\n", ipsp->iss_fin);
1210 	PRINTF("%lu\tTCP FSM\n", ipsp->iss_tcp_fsm);
1211 	PRINTF("%lu\tTCP strict\n", ipsp->iss_tcp_strict);
1212 	PRINTF("%lu\tTCP wild\n", ipsp->iss_wild);
1213 	PRINTF("%lu\tMicrosoft Windows SACK\n", ipsp->iss_winsack);
1214 
1215 	PRINTF("State logging %sabled\n", state_logging ? "en" : "dis");
1216 
1217 	PRINTF("IP states added:\n");
1218 	for (i = 0; i < 256; i++) {
1219 		if (ipsp->iss_proto[i] != 0) {
1220 			struct protoent *proto;
1221 
1222 			proto = getprotobynumber(i);
1223 			PRINTF("%lu", ipsp->iss_proto[i]);
1224 			if (proto != NULL)
1225 				PRINTF("\t%s\n", proto->p_name);
1226 			else
1227 				PRINTF("\t%d\n", i);
1228 		}
1229 	}
1230 
1231 	PRINTF("\nState table bucket statistics:\n");
1232 	PRINTF("%u\tin use\n", ipsp->iss_inuse);
1233 
1234 	minlen = ipsp->iss_max;
1235 	totallen = 0;
1236 	maxlen = 0;
1237 
1238 	for (i = 0; i < ipsp->iss_state_size; i++) {
1239 		if (buckets[i] > maxlen)
1240 			maxlen = buckets[i];
1241 		if (buckets[i] < minlen)
1242 			minlen = buckets[i];
1243 		totallen += buckets[i];
1244 	}
1245 
1246 	PRINTF("%d\thash efficiency\n",
1247 		totallen ? ipsp->iss_inuse * 100 / totallen : 0);
1248 	PRINTF("%2.2f%%\tbucket usage\n%u\tminimal length\n",
1249 		((float)ipsp->iss_inuse / ipsp->iss_state_size) * 100.0,
1250 		minlen);
1251 	PRINTF("%u\tmaximal length\n%.3f\taverage length\n",
1252 		maxlen,
1253 		ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse :
1254 				  0.0);
1255 
1256 #define ENTRIES_PER_LINE 5
1257 
1258 	if (opts & OPT_VERBOSE) {
1259 		PRINTF("\nCurrent bucket sizes :\n");
1260 		for (i = 0; i < ipsp->iss_state_size; i++) {
1261 			if ((i % ENTRIES_PER_LINE) == 0)
1262 				PRINTF("\t");
1263 			PRINTF("%4d -> %4u", i, buckets[i]);
1264 			if ((i % ENTRIES_PER_LINE) ==
1265 			    (ENTRIES_PER_LINE - 1))
1266 				PRINTF("\n");
1267 			else
1268 				PRINTF("  ");
1269 		}
1270 		PRINTF("\n");
1271 	}
1272 	PRINTF("\n");
1273 
1274 	free(buckets);
1275 
1276 	if (live_kernel == 1) {
1277 		showtqtable_live(state_fd);
1278 	} else {
1279 		printtqtable(ipsp->iss_tcptab);
1280 	}
1281 }
1282 
1283 
1284 #ifdef STATETOP
1285 static int handle_resize = 0, handle_break = 0;
1286 
topipstates(saddr,daddr,sport,dport,protocol,ver,refreshtime,topclosed,filter)1287 static void topipstates(saddr, daddr, sport, dport, protocol, ver,
1288 		        refreshtime, topclosed, filter)
1289 	i6addr_t saddr;
1290 	i6addr_t daddr;
1291 	int sport;
1292 	int dport;
1293 	int protocol;
1294 	int ver;
1295 	int refreshtime;
1296 	int topclosed;
1297 	int *filter;
1298 {
1299 	char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
1300 	int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
1301 	int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0;
1302 	int len, srclen, dstlen, forward = 1, c = 0;
1303 	ips_stat_t ipsst, *ipsstp = &ipsst;
1304 	int token_type = IPFGENITER_STATE;
1305 	statetop_t *tstable = NULL, *tp;
1306 	const char *errstr = "";
1307 	ipstate_t ips;
1308 	ipfobj_t ipfo;
1309 	struct timeval selecttimeout;
1310 	char hostnm[HOSTNMLEN];
1311 	struct protoent *proto;
1312 	fd_set readfd;
1313 	time_t t;
1314 
1315 	/* install signal handlers */
1316 	signal(SIGINT, sig_break);
1317 	signal(SIGQUIT, sig_break);
1318 	signal(SIGTERM, sig_break);
1319 	signal(SIGWINCH, sig_resize);
1320 
1321 	/* init ncurses stuff */
1322   	initscr();
1323   	cbreak();
1324   	noecho();
1325 	curs_set(0);
1326 	timeout(0);
1327 	getmaxyx(stdscr, maxy, maxx);
1328 
1329 	/* init hostname */
1330 	gethostname(hostnm, sizeof(hostnm) - 1);
1331 	hostnm[sizeof(hostnm) - 1] = '\0';
1332 
1333 	/* init ipfobj_t stuff */
1334 	bzero((caddr_t)&ipfo, sizeof(ipfo));
1335 	ipfo.ipfo_rev = IPFILTER_VERSION;
1336 	ipfo.ipfo_type = IPFOBJ_STATESTAT;
1337 	ipfo.ipfo_size = sizeof(*ipsstp);
1338 	ipfo.ipfo_ptr = (void *)ipsstp;
1339 
1340 	/* repeat until user aborts */
1341 	while ( 1 ) {
1342 
1343 		/* get state table */
1344 		bzero((char *)&ipsst, sizeof(ipsst));
1345 		if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
1346 			errstr = "ioctl(SIOCGETFS)";
1347 			ret = -1;
1348 			goto out;
1349 		}
1350 
1351 		/* clear the history */
1352 		tsentry = -1;
1353 
1354 		/* reset max str len */
1355 		srclen = dstlen = 0;
1356 
1357 		/* read the state table and store in tstable */
1358 		for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
1359 
1360 			ipsstp->iss_list = fetchstate(ipsstp->iss_list, &ips);
1361 			if (ipsstp->iss_list == NULL)
1362 				break;
1363 
1364 			if (ips.is_v != ver)
1365 				continue;
1366 
1367 			if ((filter != NULL) &&
1368 			    (state_matcharray(&ips, filter) == 0))
1369 				continue;
1370 
1371 			/* check v4 src/dest addresses */
1372 			if (ips.is_v == 4) {
1373 				if ((saddr.in4.s_addr != INADDR_ANY &&
1374 				     saddr.in4.s_addr != ips.is_saddr) ||
1375 				    (daddr.in4.s_addr != INADDR_ANY &&
1376 				     daddr.in4.s_addr != ips.is_daddr))
1377 					continue;
1378 			}
1379 #ifdef	USE_INET6
1380 			/* check v6 src/dest addresses */
1381 			if (ips.is_v == 6) {
1382 				if ((IP6_NEQ(&saddr, &in6addr_any) &&
1383 				     IP6_NEQ(&saddr, &ips.is_src)) ||
1384 				    (IP6_NEQ(&daddr, &in6addr_any) &&
1385 				     IP6_NEQ(&daddr, &ips.is_dst)))
1386 					continue;
1387 			}
1388 #endif
1389 			/* check protocol */
1390 			if (protocol > 0 && protocol != ips.is_p)
1391 				continue;
1392 
1393 			/* check ports if protocol is TCP or UDP */
1394 			if (((ips.is_p == IPPROTO_TCP) ||
1395 			     (ips.is_p == IPPROTO_UDP)) &&
1396 			   (((sport > 0) && (htons(sport) != ips.is_sport)) ||
1397 			    ((dport > 0) && (htons(dport) != ips.is_dport))))
1398 				continue;
1399 
1400 			/* show closed TCP sessions ? */
1401 			if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
1402 			    (ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
1403 			    (ips.is_state[1] >= IPF_TCPS_LAST_ACK))
1404 				continue;
1405 
1406 			/*
1407 			 * if necessary make room for this state
1408 			 * entry
1409 			 */
1410 			tsentry++;
1411 			if (!maxtsentries || tsentry == maxtsentries) {
1412 				maxtsentries += STGROWSIZE;
1413 				tstable = realloc(tstable,
1414 				    maxtsentries * sizeof(statetop_t));
1415 				if (tstable == NULL) {
1416 					perror("realloc");
1417 					exit(-1);
1418 				}
1419 			}
1420 
1421 			/* get max src/dest address string length */
1422 			len = strlen(getip(ips.is_v, &ips.is_src));
1423 			if (srclen < len)
1424 				srclen = len;
1425 			len = strlen(getip(ips.is_v, &ips.is_dst));
1426 			if (dstlen < len)
1427 				dstlen = len;
1428 
1429 			/* fill structure */
1430 			tp = tstable + tsentry;
1431 			tp->st_src = ips.is_src;
1432 			tp->st_dst = ips.is_dst;
1433 			tp->st_p = ips.is_p;
1434 			tp->st_v = ips.is_v;
1435 			tp->st_state[0] = ips.is_state[0];
1436 			tp->st_state[1] = ips.is_state[1];
1437 			if (forward) {
1438 				tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
1439 				tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
1440 			} else {
1441 				tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3];
1442 				tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3];
1443 			}
1444 			tp->st_age = ips.is_die - ipsstp->iss_ticks;
1445 			if ((ips.is_p == IPPROTO_TCP) ||
1446 			    (ips.is_p == IPPROTO_UDP)) {
1447 				tp->st_sport = ips.is_sport;
1448 				tp->st_dport = ips.is_dport;
1449 			}
1450 		}
1451 
1452 		(void) ioctl(state_fd, SIOCIPFDELTOK, &token_type);
1453 
1454 		/* sort the array */
1455 		if (tsentry != -1) {
1456 			switch (sorting)
1457 			{
1458 			case STSORT_PR:
1459 				qsort(tstable, tsentry + 1,
1460 				      sizeof(statetop_t), sort_p);
1461 				break;
1462 			case STSORT_PKTS:
1463 				qsort(tstable, tsentry + 1,
1464 				      sizeof(statetop_t), sort_pkts);
1465 				break;
1466 			case STSORT_BYTES:
1467 				qsort(tstable, tsentry + 1,
1468 				      sizeof(statetop_t), sort_bytes);
1469 				break;
1470 			case STSORT_TTL:
1471 				qsort(tstable, tsentry + 1,
1472 				      sizeof(statetop_t), sort_ttl);
1473 				break;
1474 			case STSORT_SRCIP:
1475 				qsort(tstable, tsentry + 1,
1476 				      sizeof(statetop_t), sort_srcip);
1477 				break;
1478 			case STSORT_SRCPT:
1479 				qsort(tstable, tsentry +1,
1480 					sizeof(statetop_t), sort_srcpt);
1481 				break;
1482 			case STSORT_DSTIP:
1483 				qsort(tstable, tsentry + 1,
1484 				      sizeof(statetop_t), sort_dstip);
1485 				break;
1486 			case STSORT_DSTPT:
1487 				qsort(tstable, tsentry + 1,
1488 				      sizeof(statetop_t), sort_dstpt);
1489 				break;
1490 			default:
1491 				break;
1492 			}
1493 		}
1494 
1495 		/* handle window resizes */
1496 		if (handle_resize) {
1497 			endwin();
1498 			initscr();
1499 			cbreak();
1500 			noecho();
1501 			curs_set(0);
1502 			timeout(0);
1503 			getmaxyx(stdscr, maxy, maxx);
1504 			redraw = 1;
1505 			handle_resize = 0;
1506                 }
1507 
1508 		/* stop program? */
1509 		if (handle_break)
1510 			break;
1511 
1512 		/* print title */
1513 		erase();
1514 		attron(A_BOLD);
1515 		winy = 0;
1516 		move(winy,0);
1517 		sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION);
1518 		for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
1519 			printw(" ");
1520 		printw("%s", str1);
1521 		attroff(A_BOLD);
1522 
1523 		/* just for fun add a clock */
1524 		move(winy, maxx - 8);
1525 		t = time(NULL);
1526 		strftime(str1, 80, "%T", localtime(&t));
1527 		printw("%s\n", str1);
1528 
1529 		/*
1530 		 * print the display filters, this is placed in the loop,
1531 		 * because someday I might add code for changing these
1532 		 * while the programming is running :-)
1533 		 */
1534 		if (sport >= 0)
1535 			sprintf(str1, "%s,%d", getip(ver, &saddr), sport);
1536 		else
1537 			sprintf(str1, "%s", getip(ver, &saddr));
1538 
1539 		if (dport >= 0)
1540 			sprintf(str2, "%s,%d", getip(ver, &daddr), dport);
1541 		else
1542 			sprintf(str2, "%s", getip(ver, &daddr));
1543 
1544 		if (protocol < 0)
1545 			strcpy(str3, "any");
1546 		else if ((proto = getprotobynumber(protocol)) != NULL)
1547 			sprintf(str3, "%s", proto->p_name);
1548 		else
1549 			sprintf(str3, "%d", protocol);
1550 
1551 		switch (sorting)
1552 		{
1553 		case STSORT_PR:
1554 			sprintf(str4, "proto");
1555 			break;
1556 		case STSORT_PKTS:
1557 			sprintf(str4, "# pkts");
1558 			break;
1559 		case STSORT_BYTES:
1560 			sprintf(str4, "# bytes");
1561 			break;
1562 		case STSORT_TTL:
1563 			sprintf(str4, "ttl");
1564 			break;
1565 		case STSORT_SRCIP:
1566 			sprintf(str4, "src ip");
1567 			break;
1568 		case STSORT_SRCPT:
1569 			sprintf(str4, "src port");
1570 			break;
1571 		case STSORT_DSTIP:
1572 			sprintf(str4, "dest ip");
1573 			break;
1574 		case STSORT_DSTPT:
1575 			sprintf(str4, "dest port");
1576 			break;
1577 		default:
1578 			sprintf(str4, "unknown");
1579 			break;
1580 		}
1581 
1582 		if (reverse)
1583 			strcat(str4, " (reverse)");
1584 
1585 		winy += 2;
1586 		move(winy,0);
1587 		printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
1588 		       str1, str2, str3, str4);
1589 
1590 		/*
1591 		 * For an IPv4 IP address we need at most 15 characters,
1592 		 * 4 tuples of 3 digits, separated by 3 dots. Enforce this
1593 		 * length, so the colums do not change positions based
1594 		 * on the size of the IP address. This length makes the
1595 		 * output fit in a 80 column terminal.
1596 		 * We are lacking a good solution for IPv6 addresses (that
1597 		 * can be longer that 15 characters), so we do not enforce
1598 		 * a maximum on the IP field size.
1599 		 */
1600 		if (srclen < 15)
1601 			srclen = 15;
1602 		if (dstlen < 15)
1603 			dstlen = 15;
1604 
1605 		/* print column description */
1606 		winy += 2;
1607 		move(winy,0);
1608 		attron(A_BOLD);
1609 		printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
1610 		       srclen + 6, "Source IP", dstlen + 6, "Destination IP",
1611 		       "ST", "PR", "#pkts", "#bytes", "ttl");
1612 		attroff(A_BOLD);
1613 
1614 		/* print all the entries */
1615 		tp = tstable;
1616 		if (reverse)
1617 			tp += tsentry;
1618 
1619 		if (tsentry > maxy - 6)
1620 			tsentry = maxy - 6;
1621 		for (i = 0; i <= tsentry; i++) {
1622 			/* print src/dest and port */
1623 			if ((tp->st_p == IPPROTO_TCP) ||
1624 			    (tp->st_p == IPPROTO_UDP)) {
1625 				sprintf(str1, "%s,%hu",
1626 					getip(tp->st_v, &tp->st_src),
1627 					ntohs(tp->st_sport));
1628 				sprintf(str2, "%s,%hu",
1629 					getip(tp->st_v, &tp->st_dst),
1630 					ntohs(tp->st_dport));
1631 			} else {
1632 				sprintf(str1, "%s", getip(tp->st_v,
1633 				    &tp->st_src));
1634 				sprintf(str2, "%s", getip(tp->st_v,
1635 				    &tp->st_dst));
1636 			}
1637 			winy++;
1638 			move(winy, 0);
1639 			printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
1640 
1641 			/* print state */
1642 			sprintf(str1, "%X/%X", tp->st_state[0],
1643 				tp->st_state[1]);
1644 			printw(" %3s", str1);
1645 
1646 			/* print protocol */
1647 			proto = getprotobynumber(tp->st_p);
1648 			if (proto) {
1649 				strncpy(str1, proto->p_name, 4);
1650 				str1[4] = '\0';
1651 			} else {
1652 				sprintf(str1, "%d", tp->st_p);
1653 			}
1654 			/* just print icmp for IPv6-ICMP */
1655 			if (tp->st_p == IPPROTO_ICMPV6)
1656 				strcpy(str1, "icmp");
1657 			printw(" %4s", str1);
1658 
1659 			/* print #pkt/#bytes */
1660 #ifdef	USE_QUAD_T
1661 			printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
1662 				(unsigned long long) tp->st_bytes);
1663 #else
1664 			printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
1665 #endif
1666 			printw(" %9s", ttl_to_string(tp->st_age));
1667 
1668 			if (reverse)
1669 				tp--;
1670 			else
1671 				tp++;
1672 		}
1673 
1674 		/* screen data structure is filled, now update the screen */
1675 		if (redraw)
1676 			clearok(stdscr,1);
1677 
1678 		if (refresh() == ERR)
1679 			break;
1680 		if (redraw) {
1681 			clearok(stdscr,0);
1682 			redraw = 0;
1683 		}
1684 
1685 		/* wait for key press or a 1 second time out period */
1686 		selecttimeout.tv_sec = refreshtime;
1687 		selecttimeout.tv_usec = 0;
1688 		FD_ZERO(&readfd);
1689 		FD_SET(0, &readfd);
1690 		select(1, &readfd, NULL, NULL, &selecttimeout);
1691 
1692 		/* if key pressed, read all waiting keys */
1693 		if (FD_ISSET(0, &readfd)) {
1694 			c = wgetch(stdscr);
1695 			if (c == ERR)
1696 				continue;
1697 
1698 			if (ISALPHA(c) && ISUPPER(c))
1699 				c = TOLOWER(c);
1700 			if (c == 'l') {
1701 				redraw = 1;
1702 			} else if (c == 'q') {
1703 				break;
1704 			} else if (c == 'r') {
1705 				reverse = !reverse;
1706 			} else if (c == 'b') {
1707 				forward = 0;
1708 			} else if (c == 'f') {
1709 				forward = 1;
1710 			} else if (c == 's') {
1711 				if (++sorting > STSORT_MAX)
1712 					sorting = 0;
1713 			}
1714 		}
1715 	} /* while */
1716 
1717 out:
1718 	printw("\n");
1719 	curs_set(1);
1720 	/* nocbreak(); XXX - endwin() should make this redundant */
1721 	endwin();
1722 
1723 	free(tstable);
1724 	if (ret != 0)
1725 		perror(errstr);
1726 }
1727 #endif
1728 
1729 
1730 /*
1731  * Show fragment cache information that's held in the kernel.
1732  */
showfrstates(ifsp,ticks)1733 static void showfrstates(ifsp, ticks)
1734 	ipfrstat_t *ifsp;
1735 	u_long ticks;
1736 {
1737 	struct ipfr *ipfrtab[IPFT_SIZE], ifr;
1738 	int i;
1739 
1740 	/*
1741 	 * print out the numeric statistics
1742 	 */
1743 	PRINTF("IP fragment states:\n%lu\tnew\n%lu\texpired\n%lu\thits\n",
1744 		ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
1745 	PRINTF("%lu\tretrans\n%lu\ttoo short\n",
1746 		ifsp->ifs_retrans0, ifsp->ifs_short);
1747 	PRINTF("%lu\tno memory\n%lu\talready exist\n",
1748 		ifsp->ifs_nomem, ifsp->ifs_exists);
1749 	PRINTF("%lu\tinuse\n", ifsp->ifs_inuse);
1750 	PRINTF("\n");
1751 
1752 	if (live_kernel == 0) {
1753 		if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table,
1754 			    sizeof(ipfrtab)))
1755 			return;
1756 	}
1757 
1758 	/*
1759 	 * Print out the contents (if any) of the fragment cache table.
1760 	 */
1761 	if (live_kernel == 1) {
1762 		do {
1763 			if (fetchfrag(ipf_fd, IPFGENITER_FRAG, &ifr) != 0)
1764 				break;
1765 			if (ifr.ipfr_ifp == NULL)
1766 				break;
1767 			ifr.ipfr_ttl -= ticks;
1768 			printfraginfo("", &ifr);
1769 		} while (ifr.ipfr_next != NULL);
1770 	} else {
1771 		for (i = 0; i < IPFT_SIZE; i++)
1772 			while (ipfrtab[i] != NULL) {
1773 				if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1774 					    sizeof(ifr)) == -1)
1775 					break;
1776 				printfraginfo("", &ifr);
1777 				ipfrtab[i] = ifr.ipfr_next;
1778 			}
1779 	}
1780 	/*
1781 	 * Print out the contents (if any) of the NAT fragment cache table.
1782 	 */
1783 
1784 	if (live_kernel == 0) {
1785 		if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,
1786 			    sizeof(ipfrtab)))
1787 			return;
1788 	}
1789 
1790 	if (live_kernel == 1) {
1791 		do {
1792 			if (fetchfrag(nat_fd, IPFGENITER_NATFRAG, &ifr) != 0)
1793 				break;
1794 			if (ifr.ipfr_ifp == NULL)
1795 				break;
1796 			ifr.ipfr_ttl -= ticks;
1797 			printfraginfo("NAT: ", &ifr);
1798 		} while (ifr.ipfr_next != NULL);
1799 	} else {
1800 		for (i = 0; i < IPFT_SIZE; i++)
1801 			while (ipfrtab[i] != NULL) {
1802 				if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1803 					    sizeof(ifr)) == -1)
1804 					break;
1805 				printfraginfo("NAT: ", &ifr);
1806 				ipfrtab[i] = ifr.ipfr_next;
1807 			}
1808 	}
1809 }
1810 
1811 
1812 /*
1813  * Show stats on how auth within IPFilter has been used
1814  */
showauthstates(asp)1815 static void showauthstates(asp)
1816 	ipf_authstat_t *asp;
1817 {
1818 	frauthent_t *frap, fra;
1819 	ipfgeniter_t auth;
1820 	ipfobj_t obj;
1821 
1822 	obj.ipfo_rev = IPFILTER_VERSION;
1823 	obj.ipfo_type = IPFOBJ_GENITER;
1824 	obj.ipfo_size = sizeof(auth);
1825 	obj.ipfo_ptr = &auth;
1826 
1827 	auth.igi_type = IPFGENITER_AUTH;
1828 	auth.igi_nitems = 1;
1829 	auth.igi_data = &fra;
1830 
1831 #ifdef	USE_QUAD_T
1832 	printf("Authorisation hits: %llu\tmisses %llu\n",
1833 		(unsigned long long) asp->fas_hits,
1834 		(unsigned long long) asp->fas_miss);
1835 #else
1836 	printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
1837 		asp->fas_miss);
1838 #endif
1839 	printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
1840 		asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
1841 		asp->fas_sendok);
1842 	printf("queok %ld\nquefail %ld\nexpire %ld\n",
1843 		asp->fas_queok, asp->fas_quefail, asp->fas_expire);
1844 
1845 	frap = asp->fas_faelist;
1846 	while (frap) {
1847 		if (live_kernel == 1) {
1848 			if (ioctl(auth_fd, SIOCGENITER, &obj))
1849 				break;
1850 		} else {
1851 			if (kmemcpy((char *)&fra, (u_long)frap,
1852 				    sizeof(fra)) == -1)
1853 				break;
1854 		}
1855 		printf("age %ld\t", fra.fae_age);
1856 		printfr(&fra.fae_fr, ioctl);
1857 		frap = fra.fae_next;
1858 	}
1859 }
1860 
1861 
1862 /*
1863  * Display groups used for each of filter rules, accounting rules and
1864  * authentication, separately.
1865  */
showgroups(fiop)1866 static void showgroups(fiop)
1867 	struct friostat	*fiop;
1868 {
1869 	static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
1870 	static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH };
1871 	frgroup_t *fp, grp;
1872 	int on, off, i;
1873 
1874 	on = fiop->f_active;
1875 	off = 1 - on;
1876 
1877 	for (i = 0; i < 3; i++) {
1878 		printf("%s groups (active):\n", gnames[i]);
1879 		for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL;
1880 		     fp = grp.fg_next)
1881 			if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1882 				break;
1883 			else
1884 				printf("%s\n", grp.fg_name);
1885 		printf("%s groups (inactive):\n", gnames[i]);
1886 		for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL;
1887 		     fp = grp.fg_next)
1888 			if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1889 				break;
1890 			else
1891 				printf("%s\n", grp.fg_name);
1892 	}
1893 }
1894 
1895 
parse_ipportstr(argument,ip,port)1896 static void parse_ipportstr(argument, ip, port)
1897 	const char *argument;
1898 	i6addr_t *ip;
1899 	int *port;
1900 {
1901 	char *s, *comma;
1902 	int ok = 0;
1903 
1904 	/* make working copy of argument, Theoretically you must be able
1905 	 * to write to optarg, but that seems very ugly to me....
1906 	 */
1907 	s = strdup(argument);
1908 	if (s == NULL)
1909 		return;
1910 
1911 	/* get port */
1912 	if ((comma = strchr(s, ',')) != NULL) {
1913 		if (!strcasecmp(comma + 1, "any")) {
1914 			*port = -1;
1915 		} else if (!sscanf(comma + 1, "%d", port) ||
1916 			   (*port < 0) || (*port > 65535)) {
1917 			fprintf(stderr, "Invalid port specification in %s\n",
1918 				argument);
1919 			free(s);
1920 			exit(-2);
1921 		}
1922 		*comma = '\0';
1923 	}
1924 
1925 
1926 	/* get ip address */
1927 	if (!strcasecmp(s, "any")) {
1928 		ip->in4.s_addr = INADDR_ANY;
1929 		ok = 1;
1930 #ifdef	USE_INET6
1931 		ip->in6 = in6addr_any;
1932 	} else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) {
1933 		ok = 1;
1934 #endif
1935 	} else if (inet_aton(s, &ip->in4))
1936 		ok = 1;
1937 
1938 	if (ok == 0) {
1939 		fprintf(stderr, "Invalid IP address: %s\n", s);
1940 		free(s);
1941 		exit(-2);
1942 	}
1943 
1944 	/* free allocated memory */
1945 	free(s);
1946 }
1947 
1948 
1949 #ifdef STATETOP
sig_resize(s)1950 static void sig_resize(s)
1951 	int s;
1952 {
1953 	handle_resize = 1;
1954 }
1955 
sig_break(s)1956 static void sig_break(s)
1957 	int s;
1958 {
1959 	handle_break = 1;
1960 }
1961 
getip(v,addr)1962 static char *getip(v, addr)
1963 	int v;
1964 	i6addr_t *addr;
1965 {
1966 #ifdef  USE_INET6
1967 	static char hostbuf[MAXHOSTNAMELEN+1];
1968 #endif
1969 
1970 	if (v == 4)
1971 		return inet_ntoa(addr->in4);
1972 
1973 #ifdef  USE_INET6
1974 	(void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1);
1975 	hostbuf[MAXHOSTNAMELEN] = '\0';
1976 	return hostbuf;
1977 #else
1978 	return "IPv6";
1979 #endif
1980 }
1981 
1982 
ttl_to_string(ttl)1983 static char *ttl_to_string(ttl)
1984 	long int ttl;
1985 {
1986 	static char ttlbuf[STSTRSIZE];
1987 	int hours, minutes, seconds;
1988 
1989 	/* ttl is in half seconds */
1990 	ttl /= 2;
1991 
1992 	hours = ttl / 3600;
1993 	ttl = ttl % 3600;
1994 	minutes = ttl / 60;
1995 	seconds = ttl % 60;
1996 
1997 	if (hours > 0)
1998 		sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds);
1999 	else
2000 		sprintf(ttlbuf, "%2d:%02d", minutes, seconds);
2001 	return ttlbuf;
2002 }
2003 
2004 
sort_pkts(a,b)2005 static int sort_pkts(a, b)
2006 	const void *a;
2007 	const void *b;
2008 {
2009 
2010 	register const statetop_t *ap = a;
2011 	register const statetop_t *bp = b;
2012 
2013 	if (ap->st_pkts == bp->st_pkts)
2014 		return 0;
2015 	else if (ap->st_pkts < bp->st_pkts)
2016 		return 1;
2017 	return -1;
2018 }
2019 
2020 
sort_bytes(a,b)2021 static int sort_bytes(a, b)
2022 	const void *a;
2023 	const void *b;
2024 {
2025 	register const statetop_t *ap = a;
2026 	register const statetop_t *bp = b;
2027 
2028 	if (ap->st_bytes == bp->st_bytes)
2029 		return 0;
2030 	else if (ap->st_bytes < bp->st_bytes)
2031 		return 1;
2032 	return -1;
2033 }
2034 
2035 
sort_p(a,b)2036 static int sort_p(a, b)
2037 	const void *a;
2038 	const void *b;
2039 {
2040 	register const statetop_t *ap = a;
2041 	register const statetop_t *bp = b;
2042 
2043 	if (ap->st_p == bp->st_p)
2044 		return 0;
2045 	else if (ap->st_p < bp->st_p)
2046 		return 1;
2047 	return -1;
2048 }
2049 
2050 
sort_ttl(a,b)2051 static int sort_ttl(a, b)
2052 	const void *a;
2053 	const void *b;
2054 {
2055 	register const statetop_t *ap = a;
2056 	register const statetop_t *bp = b;
2057 
2058 	if (ap->st_age == bp->st_age)
2059 		return 0;
2060 	else if (ap->st_age < bp->st_age)
2061 		return 1;
2062 	return -1;
2063 }
2064 
sort_srcip(a,b)2065 static int sort_srcip(a, b)
2066 	const void *a;
2067 	const void *b;
2068 {
2069 	register const statetop_t *ap = a;
2070 	register const statetop_t *bp = b;
2071 
2072 #ifdef USE_INET6
2073 	if (use_inet6) {
2074 		if (IP6_EQ(&ap->st_src, &bp->st_src))
2075 			return 0;
2076 		else if (IP6_GT(&ap->st_src, &bp->st_src))
2077 			return 1;
2078 	} else
2079 #endif
2080 	{
2081 		if (ntohl(ap->st_src.in4.s_addr) ==
2082 		    ntohl(bp->st_src.in4.s_addr))
2083 			return 0;
2084 		else if (ntohl(ap->st_src.in4.s_addr) >
2085 		         ntohl(bp->st_src.in4.s_addr))
2086 			return 1;
2087 	}
2088 	return -1;
2089 }
2090 
sort_srcpt(a,b)2091 static int sort_srcpt(a, b)
2092 	const void *a;
2093 	const void *b;
2094 {
2095 	register const statetop_t *ap = a;
2096 	register const statetop_t *bp = b;
2097 
2098 	if (htons(ap->st_sport) == htons(bp->st_sport))
2099 		return 0;
2100 	else if (htons(ap->st_sport) > htons(bp->st_sport))
2101 		return 1;
2102 	return -1;
2103 }
2104 
sort_dstip(a,b)2105 static int sort_dstip(a, b)
2106 	const void *a;
2107 	const void *b;
2108 {
2109 	register const statetop_t *ap = a;
2110 	register const statetop_t *bp = b;
2111 
2112 #ifdef USE_INET6
2113 	if (use_inet6) {
2114 		if (IP6_EQ(&ap->st_dst, &bp->st_dst))
2115 			return 0;
2116 		else if (IP6_GT(&ap->st_dst, &bp->st_dst))
2117 			return 1;
2118 	} else
2119 #endif
2120 	{
2121 		if (ntohl(ap->st_dst.in4.s_addr) ==
2122 		    ntohl(bp->st_dst.in4.s_addr))
2123 			return 0;
2124 		else if (ntohl(ap->st_dst.in4.s_addr) >
2125 		         ntohl(bp->st_dst.in4.s_addr))
2126 			return 1;
2127 	}
2128 	return -1;
2129 }
2130 
sort_dstpt(a,b)2131 static int sort_dstpt(a, b)
2132 	const void *a;
2133 	const void *b;
2134 {
2135 	register const statetop_t *ap = a;
2136 	register const statetop_t *bp = b;
2137 
2138 	if (htons(ap->st_dport) == htons(bp->st_dport))
2139 		return 0;
2140 	else if (htons(ap->st_dport) > htons(bp->st_dport))
2141 		return 1;
2142 	return -1;
2143 }
2144 
2145 #endif
2146 
2147 
fetchstate(src,dst)2148 ipstate_t *fetchstate(src, dst)
2149 	ipstate_t *src, *dst;
2150 {
2151 
2152 	if (live_kernel == 1) {
2153 		ipfgeniter_t state;
2154 		ipfobj_t obj;
2155 
2156 		obj.ipfo_rev = IPFILTER_VERSION;
2157 		obj.ipfo_type = IPFOBJ_GENITER;
2158 		obj.ipfo_size = sizeof(state);
2159 		obj.ipfo_ptr = &state;
2160 
2161 		state.igi_type = IPFGENITER_STATE;
2162 		state.igi_nitems = 1;
2163 		state.igi_data = dst;
2164 
2165 		if (ioctl(state_fd, SIOCGENITER, &obj) != 0)
2166 			return NULL;
2167 		if (dst->is_next == NULL) {
2168 			int n = IPFGENITER_STATE;
2169 			(void) ioctl(ipf_fd,SIOCIPFDELTOK, &n);
2170 		}
2171 	} else {
2172 		if (kmemcpy((char *)dst, (u_long)src, sizeof(*dst)))
2173 			return NULL;
2174 	}
2175 	return dst;
2176 }
2177 
2178 
fetchfrag(fd,type,frp)2179 static int fetchfrag(fd, type, frp)
2180 	int fd, type;
2181 	ipfr_t *frp;
2182 {
2183 	ipfgeniter_t frag;
2184 	ipfobj_t obj;
2185 
2186 	obj.ipfo_rev = IPFILTER_VERSION;
2187 	obj.ipfo_type = IPFOBJ_GENITER;
2188 	obj.ipfo_size = sizeof(frag);
2189 	obj.ipfo_ptr = &frag;
2190 
2191 	frag.igi_type = type;
2192 	frag.igi_nitems = 1;
2193 	frag.igi_data = frp;
2194 
2195 	if (ioctl(fd, SIOCGENITER, &obj))
2196 		return EFAULT;
2197 	return 0;
2198 }
2199 
2200 
state_matcharray(stp,array)2201 static int state_matcharray(stp, array)
2202 	ipstate_t *stp;
2203 	int *array;
2204 {
2205 	int i, n, *x, rv, p;
2206 	ipfexp_t *e;
2207 
2208 	rv = 0;
2209 
2210 	for (n = array[0], x = array + 1; n > 0; x += e->ipfe_size) {
2211 		e = (ipfexp_t *)x;
2212 		if (e->ipfe_cmd == IPF_EXP_END)
2213 			break;
2214 		n -= e->ipfe_size;
2215 
2216 		rv = 0;
2217 		/*
2218 		 * The upper 16 bits currently store the protocol value.
2219 		 * This is currently used with TCP and UDP port compares and
2220 		 * allows "tcp.port = 80" without requiring an explicit
2221 		 " "ip.pr = tcp" first.
2222 		 */
2223 		p = e->ipfe_cmd >> 16;
2224 		if ((p != 0) && (p != stp->is_p))
2225 			break;
2226 
2227 		switch (e->ipfe_cmd)
2228 		{
2229 		case IPF_EXP_IP_PR :
2230 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2231 				rv |= (stp->is_p == e->ipfe_arg0[i]);
2232 			}
2233 			break;
2234 
2235 		case IPF_EXP_IP_SRCADDR :
2236 			if (stp->is_v != 4)
2237 				break;
2238 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2239 				rv |= ((stp->is_saddr &
2240 					e->ipfe_arg0[i * 2 + 1]) ==
2241 				       e->ipfe_arg0[i * 2]);
2242 			}
2243 			break;
2244 
2245 		case IPF_EXP_IP_DSTADDR :
2246 			if (stp->is_v != 4)
2247 				break;
2248 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2249 				rv |= ((stp->is_daddr &
2250 					e->ipfe_arg0[i * 2 + 1]) ==
2251 				       e->ipfe_arg0[i * 2]);
2252 			}
2253 			break;
2254 
2255 		case IPF_EXP_IP_ADDR :
2256 			if (stp->is_v != 4)
2257 				break;
2258 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2259 				rv |= ((stp->is_saddr &
2260 					e->ipfe_arg0[i * 2 + 1]) ==
2261 				       e->ipfe_arg0[i * 2]) ||
2262 				      ((stp->is_daddr &
2263 					e->ipfe_arg0[i * 2 + 1]) ==
2264 				       e->ipfe_arg0[i * 2]);
2265 			}
2266 			break;
2267 
2268 #ifdef USE_INET6
2269 		case IPF_EXP_IP6_SRCADDR :
2270 			if (stp->is_v != 6)
2271 				break;
2272 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2273 				rv |= IP6_MASKEQ(&stp->is_src,
2274 						 &e->ipfe_arg0[i * 8 + 4],
2275 						 &e->ipfe_arg0[i * 8]);
2276 			}
2277 			break;
2278 
2279 		case IPF_EXP_IP6_DSTADDR :
2280 			if (stp->is_v != 6)
2281 				break;
2282 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2283 				rv |= IP6_MASKEQ(&stp->is_dst,
2284 						 &e->ipfe_arg0[i * 8 + 4],
2285 						 &e->ipfe_arg0[i * 8]);
2286 			}
2287 			break;
2288 
2289 		case IPF_EXP_IP6_ADDR :
2290 			if (stp->is_v != 6)
2291 				break;
2292 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2293 				rv |= IP6_MASKEQ(&stp->is_src,
2294 						 &e->ipfe_arg0[i * 8 + 4],
2295 						 &e->ipfe_arg0[i * 8]) ||
2296 				      IP6_MASKEQ(&stp->is_dst,
2297 						 &e->ipfe_arg0[i * 8 + 4],
2298 						 &e->ipfe_arg0[i * 8]);
2299 			}
2300 			break;
2301 #endif
2302 
2303 		case IPF_EXP_UDP_PORT :
2304 		case IPF_EXP_TCP_PORT :
2305 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2306 				rv |= (stp->is_sport == e->ipfe_arg0[i]) ||
2307 				      (stp->is_dport == e->ipfe_arg0[i]);
2308 			}
2309 			break;
2310 
2311 		case IPF_EXP_UDP_SPORT :
2312 		case IPF_EXP_TCP_SPORT :
2313 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2314 				rv |= (stp->is_sport == e->ipfe_arg0[i]);
2315 			}
2316 			break;
2317 
2318 		case IPF_EXP_UDP_DPORT :
2319 		case IPF_EXP_TCP_DPORT :
2320 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2321 				rv |= (stp->is_dport == e->ipfe_arg0[i]);
2322 			}
2323 			break;
2324 
2325 		case IPF_EXP_IDLE_GT :
2326 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2327 				rv |= (stp->is_die < e->ipfe_arg0[i]);
2328 			}
2329 			break;
2330 
2331 		case IPF_EXP_TCP_STATE :
2332 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
2333 				rv |= (stp->is_state[0] == e->ipfe_arg0[i]) ||
2334 				      (stp->is_state[1] == e->ipfe_arg0[i]);
2335 			}
2336 			break;
2337 		}
2338 		rv ^= e->ipfe_not;
2339 
2340 		if (rv == 0)
2341 			break;
2342 	}
2343 
2344 	return rv;
2345 }
2346 
2347 
showtqtable_live(fd)2348 static void showtqtable_live(fd)
2349 	int fd;
2350 {
2351 	ipftq_t table[IPF_TCP_NSTATES];
2352 	ipfobj_t obj;
2353 
2354 	bzero((char *)&obj, sizeof(obj));
2355 	obj.ipfo_rev = IPFILTER_VERSION;
2356 	obj.ipfo_size = sizeof(table);
2357 	obj.ipfo_ptr = (void *)table;
2358 	obj.ipfo_type = IPFOBJ_STATETQTAB;
2359 
2360 	if (ioctl(fd, SIOCGTQTAB, &obj) == 0) {
2361 		printtqtable(table);
2362 	}
2363 }
2364