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