Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ipf / tools / ipfstat.c
blob1bf74e485af0af183011270e7ead0471c30c6822
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2002-2006 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 * Copyright 2008 Sun Microsystems, Inc.
9 */
10 #ifdef __FreeBSD__
11 # ifndef __FreeBSD_cc_version
12 # include <osreldate.h>
13 # else
14 # if __FreeBSD_cc_version < 430000
15 # include <osreldate.h>
16 # endif
17 # endif
18 #endif
19 #include <sys/ioctl.h>
20 #include <fcntl.h>
21 #ifdef linux
22 # include <linux/a.out.h>
23 #else
24 # include <nlist.h>
25 #endif
26 #include <ctype.h>
27 #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
28 # include <stddef.h>
29 #endif
30 #include "ipf.h"
31 #include "netinet/ipl.h"
32 #if defined(STATETOP)
33 # if defined(_BSDI_VERSION)
34 # undef STATETOP
35 # endif
36 # if defined(__FreeBSD__) && \
37 (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000))
38 # undef STATETOP
39 # endif
40 # if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105000000)
41 # undef STATETOP
42 # endif
43 # if defined(sun)
44 # if defined(__svr4__) || defined(__SVR4)
45 # include <sys/select.h>
46 # else
47 # undef STATETOP /* NOT supported on SunOS4 */
48 # endif
49 # endif
50 #endif
51 #if defined(STATETOP) && !defined(linux)
52 # include <netinet/ip_var.h>
53 # include <netinet/tcp_fsm.h>
54 #endif
55 #ifdef STATETOP
56 # include <ctype.h>
57 # include <signal.h>
58 # include <time.h>
59 # if SOLARIS || defined(__NetBSD__) || defined(_BSDI_VERSION) || \
60 defined(__sgi)
61 # ifdef ERR
62 # undef ERR
63 # endif
64 # include <curses.h>
65 # else /* SOLARIS */
66 # include <ncurses.h>
67 # endif /* SOLARIS */
68 #endif /* STATETOP */
69 #include "kmem.h"
70 #if defined(__NetBSD__) || (__OpenBSD__)
71 # include <paths.h>
72 #endif
74 #if !defined(lint)
75 static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed";
76 static const char rcsid[] = "@(#)Id: ipfstat.c,v 1.44.2.27 2009/07/21 09:13:13 darrenr Exp";
77 #endif
79 #ifdef __hpux
80 # define nlist nlist64
81 #endif
83 extern char *optarg;
84 extern int optind;
85 extern int opterr;
87 #define PRINTF (void)printf
88 #define FPRINTF (void)fprintf
89 static char *filters[4] = { "ipfilter(in)", "ipfilter(out)",
90 "ipacct(in)", "ipacct(out)" };
91 static int state_logging = -1;
93 int opts = 0;
94 int use_inet6 = 0;
95 int live_kernel = 1;
96 int state_fd = -1;
97 int ipf_fd = -1;
98 int auth_fd = -1;
99 int nat_fd = -1;
100 frgroup_t *grtop = NULL;
101 frgroup_t *grtail = NULL;
103 #ifdef STATETOP
104 #define STSTRSIZE 80
105 #define STGROWSIZE 16
106 #define HOSTNMLEN 40
108 #define STSORT_PR 0
109 #define STSORT_PKTS 1
110 #define STSORT_BYTES 2
111 #define STSORT_TTL 3
112 #define STSORT_SRCIP 4
113 #define STSORT_SRCPT 5
114 #define STSORT_DSTIP 6
115 #define STSORT_DSTPT 7
116 #define STSORT_MAX STSORT_DSTPT
117 #define STSORT_DEFAULT STSORT_BYTES
120 typedef struct statetop {
121 i6addr_t st_src;
122 i6addr_t st_dst;
123 u_short st_sport;
124 u_short st_dport;
125 u_char st_p;
126 u_char st_v;
127 u_char st_state[2];
128 U_QUAD_T st_pkts;
129 U_QUAD_T st_bytes;
130 u_long st_age;
131 } statetop_t;
132 #endif
134 int main __P((int, char *[]));
136 static int fetchfrag __P((int, int, ipfr_t *));
137 static void showstats __P((friostat_t *, u_32_t));
138 static void showfrstates __P((ipfrstat_t *, u_long));
139 static void showlist __P((friostat_t *));
140 static void showipstates __P((ips_stat_t *));
141 static void showauthstates __P((fr_authstat_t *));
142 static void showgroups __P((friostat_t *));
143 static void usage __P((char *));
144 static void showtqtable_live __P((int));
145 static void printlivelist __P((int, int, frentry_t *, char *, char *));
146 static void printdeadlist __P((int, int, frentry_t *, char *, char *));
147 static void parse_ipportstr __P((const char *, i6addr_t *, int *));
148 static void ipfstate_live __P((char *, friostat_t **, ips_stat_t **,
149 ipfrstat_t **, fr_authstat_t **, u_32_t *));
150 static void ipfstate_dead __P((char *, friostat_t **, ips_stat_t **,
151 ipfrstat_t **, fr_authstat_t **, u_32_t *));
152 static ipstate_t *fetchstate __P((ipstate_t *, ipstate_t *));
153 #ifdef STATETOP
154 static void topipstates __P((i6addr_t, i6addr_t, int, int, int,
155 int, int, int));
156 static void sig_break __P((int));
157 static void sig_resize __P((int));
158 static char *getip __P((int, i6addr_t *));
159 static char *ttl_to_string __P((long));
160 static int sort_p __P((const void *, const void *));
161 static int sort_pkts __P((const void *, const void *));
162 static int sort_bytes __P((const void *, const void *));
163 static int sort_ttl __P((const void *, const void *));
164 static int sort_srcip __P((const void *, const void *));
165 static int sort_srcpt __P((const void *, const void *));
166 static int sort_dstip __P((const void *, const void *));
167 static int sort_dstpt __P((const void *, const void *));
168 #endif
171 static void usage(name)
172 char *name;
174 #ifdef USE_INET6
175 fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name);
176 #else
177 fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name);
178 #endif
179 fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name);
180 #ifdef USE_INET6
181 fprintf(stderr, " %s -t [-6C] ", name);
182 #else
183 fprintf(stderr, " %s -t [-C] ", name);
184 #endif
185 fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n");
186 exit(1);
190 int main(argc,argv)
191 int argc;
192 char *argv[];
194 fr_authstat_t frauthst;
195 fr_authstat_t *frauthstp = &frauthst;
196 friostat_t fio;
197 friostat_t *fiop = &fio;
198 ips_stat_t ipsst;
199 ips_stat_t *ipsstp = &ipsst;
200 ipfrstat_t ifrst;
201 ipfrstat_t *ifrstp = &ifrst;
202 char *memf = NULL;
203 char *options, *kern = NULL;
204 int c, myoptind;
206 int protocol = -1; /* -1 = wild card for any protocol */
207 int refreshtime = 1; /* default update time */
208 int sport = -1; /* -1 = wild card for any source port */
209 int dport = -1; /* -1 = wild card for any dest port */
210 int topclosed = 0; /* do not show closed tcp sessions */
211 i6addr_t saddr, daddr;
212 u_32_t frf;
214 #ifdef USE_INET6
215 options = "6aACdfghIilnostvD:M:N:P:RS:T:";
216 #else
217 options = "aACdfghIilnostvD:M:N:P:RS:T:";
218 #endif
220 saddr.in4.s_addr = INADDR_ANY; /* default any v4 source addr */
221 daddr.in4.s_addr = INADDR_ANY; /* default any v4 dest addr */
222 #ifdef USE_INET6
223 saddr.in6 = in6addr_any; /* default any v6 source addr */
224 daddr.in6 = in6addr_any; /* default any v6 dest addr */
225 #endif
227 /* Don't warn about invalid flags when we run getopt for the 1st time */
228 opterr = 0;
231 * Parse these two arguments now lest there be any buffer overflows
232 * in the parsing of the rest.
234 myoptind = optind;
235 while ((c = getopt(argc, argv, options)) != -1) {
236 switch (c)
238 case 'M' :
239 memf = optarg;
240 live_kernel = 0;
241 break;
242 case 'N' :
243 kern = optarg;
244 live_kernel = 0;
245 break;
248 optind = myoptind;
250 if (live_kernel == 1) {
251 if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) {
252 perror("open(IPSTATE_NAME)");
253 exit(-1);
255 if ((auth_fd = open(IPAUTH_NAME, O_RDONLY)) == -1) {
256 perror("open(IPAUTH_NAME)");
257 exit(-1);
259 if ((nat_fd = open(IPNAT_NAME, O_RDONLY)) == -1) {
260 perror("open(IPAUTH_NAME)");
261 exit(-1);
263 if ((ipf_fd = open(IPL_NAME, O_RDONLY)) == -1) {
264 fprintf(stderr, "open(%s)", IPL_NAME);
265 perror("");
266 exit(-1);
270 if (kern != NULL || memf != NULL) {
271 (void)setgid(getgid());
272 (void)setuid(getuid());
275 if (live_kernel == 1) {
276 (void) checkrev(IPL_NAME);
277 } else {
278 if (openkmem(kern, memf) == -1)
279 exit(-1);
282 (void)setgid(getgid());
283 (void)setuid(getuid());
285 opterr = 1;
287 while ((c = getopt(argc, argv, options)) != -1)
289 switch (c)
291 #ifdef USE_INET6
292 case '6' :
293 use_inet6 = 1;
294 break;
295 #endif
296 case 'a' :
297 opts |= OPT_ACCNT|OPT_SHOWLIST;
298 break;
299 case 'A' :
300 opts |= OPT_AUTHSTATS;
301 break;
302 case 'C' :
303 topclosed = 1;
304 break;
305 case 'd' :
306 opts |= OPT_DEBUG;
307 break;
308 case 'D' :
309 parse_ipportstr(optarg, &daddr, &dport);
310 break;
311 case 'f' :
312 opts |= OPT_FRSTATES;
313 break;
314 case 'g' :
315 opts |= OPT_GROUPS;
316 break;
317 case 'h' :
318 opts |= OPT_HITS;
319 break;
320 case 'i' :
321 opts |= OPT_INQUE|OPT_SHOWLIST;
322 break;
323 case 'I' :
324 opts |= OPT_INACTIVE;
325 break;
326 case 'l' :
327 opts |= OPT_SHOWLIST;
328 break;
329 case 'M' :
330 break;
331 case 'N' :
332 break;
333 case 'n' :
334 opts |= OPT_SHOWLINENO;
335 break;
336 case 'o' :
337 opts |= OPT_OUTQUE|OPT_SHOWLIST;
338 break;
339 case 'P' :
340 protocol = getproto(optarg);
341 if (protocol == -1) {
342 fprintf(stderr, "%s: Invalid protocol: %s\n",
343 argv[0], optarg);
344 exit(-2);
346 break;
347 case 'R' :
348 opts |= OPT_NORESOLVE;
349 break;
350 case 's' :
351 opts |= OPT_IPSTATES;
352 break;
353 case 'S' :
354 parse_ipportstr(optarg, &saddr, &sport);
355 break;
356 case 't' :
357 #ifdef STATETOP
358 opts |= OPT_STATETOP;
359 break;
360 #else
361 fprintf(stderr,
362 "%s: state top facility not compiled in\n",
363 argv[0]);
364 exit(-2);
365 #endif
366 case 'T' :
367 if (!sscanf(optarg, "%d", &refreshtime) ||
368 (refreshtime <= 0)) {
369 fprintf(stderr,
370 "%s: Invalid refreshtime < 1 : %s\n",
371 argv[0], optarg);
372 exit(-2);
374 break;
375 case 'v' :
376 opts |= OPT_VERBOSE;
377 break;
378 default :
379 usage(argv[0]);
380 break;
384 if (live_kernel == 1) {
385 bzero((char *)&fio, sizeof(fio));
386 bzero((char *)&ipsst, sizeof(ipsst));
387 bzero((char *)&ifrst, sizeof(ifrst));
389 ipfstate_live(IPL_NAME, &fiop, &ipsstp, &ifrstp,
390 &frauthstp, &frf);
391 } else
392 ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf);
394 if (opts & OPT_IPSTATES) {
395 showipstates(ipsstp);
396 } else if (opts & OPT_SHOWLIST) {
397 showlist(fiop);
398 if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){
399 opts &= ~OPT_OUTQUE;
400 showlist(fiop);
402 } else if (opts & OPT_FRSTATES)
403 showfrstates(ifrstp, fiop->f_ticks);
404 #ifdef STATETOP
405 else if (opts & OPT_STATETOP)
406 topipstates(saddr, daddr, sport, dport, protocol,
407 use_inet6 ? 6 : 4, refreshtime, topclosed);
408 #endif
409 else if (opts & OPT_AUTHSTATS)
410 showauthstates(frauthstp);
411 else if (opts & OPT_GROUPS)
412 showgroups(fiop);
413 else
414 showstats(fiop, frf);
416 return 0;
421 * Fill in the stats structures from the live kernel, using a combination
422 * of ioctl's and copying directly from kernel memory.
424 static void ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
425 char *device;
426 friostat_t **fiopp;
427 ips_stat_t **ipsstpp;
428 ipfrstat_t **ifrstpp;
429 fr_authstat_t **frauthstpp;
430 u_32_t *frfp;
432 ipfobj_t ipfo;
434 if (checkrev(device) == -1) {
435 fprintf(stderr, "User/kernel version check failed\n");
436 exit(1);
439 if ((opts & OPT_AUTHSTATS) == 0) {
440 bzero((caddr_t)&ipfo, sizeof(ipfo));
441 ipfo.ipfo_rev = IPFILTER_VERSION;
442 ipfo.ipfo_type = IPFOBJ_IPFSTAT;
443 ipfo.ipfo_size = sizeof(friostat_t);
444 ipfo.ipfo_ptr = (void *)*fiopp;
446 if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) {
447 perror("ioctl(ipf:SIOCGETFS)");
448 exit(-1);
451 if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1)
452 perror("ioctl(SIOCGETFF)");
455 if ((opts & OPT_IPSTATES) != 0) {
457 bzero((caddr_t)&ipfo, sizeof(ipfo));
458 ipfo.ipfo_rev = IPFILTER_VERSION;
459 ipfo.ipfo_type = IPFOBJ_STATESTAT;
460 ipfo.ipfo_size = sizeof(ips_stat_t);
461 ipfo.ipfo_ptr = (void *)*ipsstpp;
463 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
464 perror("ioctl(state:SIOCGETFS)");
465 exit(-1);
467 if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) {
468 perror("ioctl(state:SIOCGETLG)");
469 exit(-1);
473 if ((opts & OPT_FRSTATES) != 0) {
474 bzero((caddr_t)&ipfo, sizeof(ipfo));
475 ipfo.ipfo_rev = IPFILTER_VERSION;
476 ipfo.ipfo_type = IPFOBJ_FRAGSTAT;
477 ipfo.ipfo_size = sizeof(ipfrstat_t);
478 ipfo.ipfo_ptr = (void *)*ifrstpp;
480 if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) {
481 perror("ioctl(SIOCGFRST)");
482 exit(-1);
486 if (opts & OPT_DEBUG)
487 PRINTF("opts %#x name %s\n", opts, device);
489 if ((opts & OPT_AUTHSTATS) != 0) {
490 bzero((caddr_t)&ipfo, sizeof(ipfo));
491 ipfo.ipfo_rev = IPFILTER_VERSION;
492 ipfo.ipfo_type = IPFOBJ_AUTHSTAT;
493 ipfo.ipfo_size = sizeof(fr_authstat_t);
494 ipfo.ipfo_ptr = (void *)*frauthstpp;
496 if (ioctl(auth_fd, SIOCATHST, &ipfo) == -1) {
497 perror("ioctl(SIOCATHST)");
498 exit(-1);
505 * Build up the stats structures from data held in the "core" memory.
506 * This is mainly useful when looking at data in crash dumps and ioctl's
507 * just won't work any more.
509 static void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
510 char *kernel;
511 friostat_t **fiopp;
512 ips_stat_t **ipsstpp;
513 ipfrstat_t **ifrstpp;
514 fr_authstat_t **frauthstpp;
515 u_32_t *frfp;
517 static fr_authstat_t frauthst, *frauthstp;
518 static ips_stat_t ipsst, *ipsstp;
519 static ipfrstat_t ifrst, *ifrstp;
520 static friostat_t fio, *fiop;
521 static ipftq_t ipssttab[IPF_TCP_NSTATES];
522 int temp;
524 void *rules[2][2];
525 struct nlist deadlist[44] = {
526 { "fr_authstats" }, /* 0 */
527 { "fae_list" },
528 { "ipauth" },
529 { "fr_authlist" },
530 { "fr_authstart" },
531 { "fr_authend" }, /* 5 */
532 { "fr_authnext" },
533 { "fr_auth" },
534 { "fr_authused" },
535 { "fr_authsize" },
536 { "fr_defaultauthage" }, /* 10 */
537 { "fr_authpkts" },
538 { "fr_auth_lock" },
539 { "frstats" },
540 { "ips_stats" },
541 { "ips_num" }, /* 15 */
542 { "ips_wild" },
543 { "ips_list" },
544 { "ips_table" },
545 { "fr_statemax" },
546 { "fr_statesize" }, /* 20 */
547 { "fr_state_doflush" },
548 { "fr_state_lock" },
549 { "ipfr_heads" },
550 { "ipfr_nattab" },
551 { "ipfr_stats" }, /* 25 */
552 { "ipfr_inuse" },
553 { "fr_ipfrttl" },
554 { "fr_frag_lock" },
555 { "ipfr_timer_id" },
556 { "fr_nat_lock" }, /* 30 */
557 { "ipfilter" },
558 { "ipfilter6" },
559 { "ipacct" },
560 { "ipacct6" },
561 { "ipl_frouteok" }, /* 35 */
562 { "fr_running" },
563 { "ipfgroups" },
564 { "fr_active" },
565 { "fr_pass" },
566 { "fr_flags" }, /* 40 */
567 { "ipstate_logging" },
568 { "ips_tqtqb" },
569 { NULL }
573 frauthstp = &frauthst;
574 ipsstp = &ipsst;
575 ifrstp = &ifrst;
576 fiop = &fio;
578 *frfp = 0;
579 *fiopp = fiop;
580 *ipsstpp = ipsstp;
581 *ifrstpp = ifrstp;
582 *frauthstpp = frauthstp;
584 bzero((char *)fiop, sizeof(*fiop));
585 bzero((char *)ipsstp, sizeof(*ipsstp));
586 bzero((char *)ifrstp, sizeof(*ifrstp));
587 bzero((char *)frauthstp, sizeof(*frauthstp));
589 if (nlist(kernel, deadlist) == -1) {
590 fprintf(stderr, "nlist error\n");
591 return;
595 * This is for SIOCGETFF.
597 kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp));
600 * f_locks is a combination of the lock variable from each part of
601 * ipfilter (state, auth, nat, fragments).
603 kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop));
604 kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value,
605 sizeof(fiop->f_locks[0]));
606 kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value,
607 sizeof(fiop->f_locks[1]));
608 kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value,
609 sizeof(fiop->f_locks[2]));
610 kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value,
611 sizeof(fiop->f_locks[3]));
614 * Get pointers to each list of rules (active, inactive, in, out)
616 kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules));
617 fiop->f_fin[0] = rules[0][0];
618 fiop->f_fin[1] = rules[0][1];
619 fiop->f_fout[0] = rules[1][0];
620 fiop->f_fout[1] = rules[1][1];
623 * Same for IPv6, except make them null if support for it is not
624 * being compiled in.
626 #ifdef USE_INET6
627 kmemcpy((char *)&rules, (u_long)deadlist[32].n_value, sizeof(rules));
628 fiop->f_fin6[0] = rules[0][0];
629 fiop->f_fin6[1] = rules[0][1];
630 fiop->f_fout6[0] = rules[1][0];
631 fiop->f_fout6[1] = rules[1][1];
632 #else
633 fiop->f_fin6[0] = NULL;
634 fiop->f_fin6[1] = NULL;
635 fiop->f_fout6[0] = NULL;
636 fiop->f_fout6[1] = NULL;
637 #endif
640 * Now get accounting rules pointers.
642 kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules));
643 fiop->f_acctin[0] = rules[0][0];
644 fiop->f_acctin[1] = rules[0][1];
645 fiop->f_acctout[0] = rules[1][0];
646 fiop->f_acctout[1] = rules[1][1];
648 #ifdef USE_INET6
649 kmemcpy((char *)&rules, (u_long)deadlist[34].n_value, sizeof(rules));
650 fiop->f_acctin6[0] = rules[0][0];
651 fiop->f_acctin6[1] = rules[0][1];
652 fiop->f_acctout6[0] = rules[1][0];
653 fiop->f_acctout6[1] = rules[1][1];
654 #else
655 fiop->f_acctin6[0] = NULL;
656 fiop->f_acctin6[1] = NULL;
657 fiop->f_acctout6[0] = NULL;
658 fiop->f_acctout6[1] = NULL;
659 #endif
662 * A collection of "global" variables used inside the kernel which
663 * are all collected in friostat_t via ioctl.
665 kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[35].n_value,
666 sizeof(fiop->f_froute));
667 kmemcpy((char *)&fiop->f_running, (u_long)deadlist[36].n_value,
668 sizeof(fiop->f_running));
669 kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[37].n_value,
670 sizeof(fiop->f_groups));
671 kmemcpy((char *)&fiop->f_active, (u_long)deadlist[38].n_value,
672 sizeof(fiop->f_active));
673 kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[39].n_value,
674 sizeof(fiop->f_defpass));
677 * Build up the state information stats structure.
679 kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp));
680 kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp));
681 kmemcpy((char *)ipssttab, (u_long)deadlist[42].n_value,
682 sizeof(ipssttab));
683 ipsstp->iss_active = temp;
684 ipsstp->iss_table = (void *)deadlist[18].n_value;
685 ipsstp->iss_list = (void *)deadlist[17].n_value;
686 ipsstp->iss_tcptab = ipssttab;
689 * Build up the authentiation information stats structure.
691 kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value,
692 sizeof(*frauthstp));
693 frauthstp->fas_faelist = (void *)deadlist[1].n_value;
696 * Build up the fragment information stats structure.
698 kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value,
699 sizeof(*ifrstp));
700 ifrstp->ifs_table = (void *)deadlist[23].n_value;
701 ifrstp->ifs_nattab = (void *)deadlist[24].n_value;
702 kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value,
703 sizeof(ifrstp->ifs_inuse));
706 * Get logging on/off switches
708 kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value,
709 sizeof(state_logging));
714 * Display the kernel stats for packets blocked and passed and other
715 * associated running totals which are kept.
717 static void showstats(fp, frf)
718 struct friostat *fp;
719 u_32_t frf;
722 PRINTF("bad packets:\t\tin %lu\tout %lu\n",
723 fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
724 #ifdef USE_INET6
725 PRINTF(" IPv6 packets:\t\tin %lu out %lu\n",
726 fp->f_st[0].fr_ipv6, fp->f_st[1].fr_ipv6);
727 #endif
728 PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
729 fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
730 fp->f_st[0].fr_nom);
731 PRINTF(" counted %lu short %lu\n",
732 fp->f_st[0].fr_acct, fp->f_st[0].fr_short);
733 PRINTF("output packets:\t\tblocked %lu passed %lu nomatch %lu",
734 fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
735 fp->f_st[1].fr_nom);
736 PRINTF(" counted %lu short %lu\n",
737 fp->f_st[1].fr_acct, fp->f_st[1].fr_short);
738 PRINTF(" input packets logged:\tblocked %lu passed %lu\n",
739 fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
740 PRINTF("output packets logged:\tblocked %lu passed %lu\n",
741 fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
742 PRINTF(" packets logged:\tinput %lu output %lu\n",
743 fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl);
744 PRINTF(" log failures:\t\tinput %lu output %lu\n",
745 fp->f_st[0].fr_skip, fp->f_st[1].fr_skip);
746 PRINTF("fragment state(in):\tkept %lu\tlost %lu\tnot fragmented %lu\n",
747 fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr,
748 fp->f_st[0].fr_cfr);
749 PRINTF("fragment state(out):\tkept %lu\tlost %lu\tnot fragmented %lu\n",
750 fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr,
751 fp->f_st[0].fr_cfr);
752 PRINTF("packet state(in):\tkept %lu\tlost %lu\n",
753 fp->f_st[0].fr_ads, fp->f_st[0].fr_bads);
754 PRINTF("packet state(out):\tkept %lu\tlost %lu\n",
755 fp->f_st[1].fr_ads, fp->f_st[1].fr_bads);
756 PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n",
757 fp->f_st[0].fr_ret, fp->f_st[1].fr_ret);
758 PRINTF("Invalid source(in):\t%lu\n", fp->f_st[0].fr_badsrc);
759 PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n",
760 fp->f_st[0].fr_chit, fp->f_st[1].fr_chit);
761 PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n",
762 fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]);
763 PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n",
764 fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]);
765 PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n",
766 fp->f_froute[0], fp->f_froute[1]);
767 PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n",
768 fp->f_st[0].fr_tcpbad, fp->f_st[1].fr_tcpbad);
769 PRINTF("IPF Ticks:\t%lu\n", fp->f_ticks);
771 PRINTF("Packet log flags set: (%#x)\n", frf);
772 if (frf & FF_LOGPASS)
773 PRINTF("\tpackets passed through filter\n");
774 if (frf & FF_LOGBLOCK)
775 PRINTF("\tpackets blocked by filter\n");
776 if (frf & FF_LOGNOMATCH)
777 PRINTF("\tpackets not matched by filter\n");
778 if (!frf)
779 PRINTF("\tnone\n");
784 * Print out a list of rules from the kernel, starting at the one passed.
786 static void printlivelist(out, set, fp, group, comment)
787 int out, set;
788 frentry_t *fp;
789 char *group, *comment;
791 struct frentry fb;
792 ipfruleiter_t rule;
793 frentry_t zero;
794 frgroup_t *g;
795 ipfobj_t obj;
796 int n;
797 void *buf;
798 size_t bufsiz;
800 if (use_inet6 == 1)
801 fb.fr_v = 6;
802 else
803 fb.fr_v = 4;
804 fb.fr_next = fp;
805 n = 0;
807 rule.iri_inout = out;
808 rule.iri_active = set;
809 rule.iri_rule = &fb;
810 rule.iri_nrules = 1;
811 rule.iri_v = use_inet6 ? 6 : 4;
812 if (group != NULL)
813 strncpy(rule.iri_group, group, FR_GROUPLEN);
814 else
815 rule.iri_group[0] = '\0';
817 bzero((char *)&zero, sizeof(zero));
819 bzero((char *)&obj, sizeof(obj));
820 obj.ipfo_rev = IPFILTER_VERSION;
821 obj.ipfo_type = IPFOBJ_IPFITER;
822 obj.ipfo_size = sizeof(rule);
823 obj.ipfo_ptr = &rule;
826 * The API does not know how much we need for filter data. Assume
827 * 10K is large enough. XXX: The code silently fails elsewhere on
828 * allocation, we do the same here.
830 if ((buf = malloc(bufsiz = sizeof(*fp) + 10240)) == NULL)
831 return;
833 do {
834 memset(buf, 0xff, bufsiz);
835 fp = buf;
836 rule.iri_rule = fp;
837 if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) {
838 perror("ioctl(SIOCIPFITER)");
839 return;
841 if (bcmp(fp, &zero, sizeof(zero)) == 0)
842 break;
843 if (fp->fr_data != NULL)
844 fp->fr_data = (char *)fp + sizeof(*fp);
846 n++;
848 if (opts & (OPT_HITS|OPT_VERBOSE))
849 #ifdef USE_QUAD_T
850 PRINTF("%qu ", (unsigned long long) fp->fr_hits);
851 #else
852 PRINTF("%lu ", fp->fr_hits);
853 #endif
854 if (opts & (OPT_ACCNT|OPT_VERBOSE))
855 #ifdef USE_QUAD_T
856 PRINTF("%qu ", (unsigned long long) fp->fr_bytes);
857 #else
858 PRINTF("%lu ", fp->fr_bytes);
859 #endif
860 if (opts & OPT_SHOWLINENO)
861 PRINTF("@%d ", n);
863 printfr(fp, ioctl);
864 if (opts & OPT_DEBUG) {
865 binprint(fp, sizeof(*fp));
866 if (fp->fr_data != NULL && fp->fr_dsize > 0)
867 binprint(fp->fr_data, fp->fr_dsize);
869 if (fp->fr_grhead[0] != '\0') {
870 for (g = grtop; g != NULL; g = g->fg_next) {
871 if (!strncmp(fp->fr_grhead, g->fg_name,
872 FR_GROUPLEN))
873 break;
875 if (g == NULL) {
876 g = calloc(1, sizeof(*g));
878 if (g != NULL) {
879 strncpy(g->fg_name, fp->fr_grhead,
880 FR_GROUPLEN);
881 if (grtop == NULL) {
882 grtop = g;
883 grtail = g;
884 } else {
885 grtail->fg_next = g;
886 grtail = g;
891 if (fp->fr_type == FR_T_CALLFUNC) {
892 printlivelist(out, set, fp->fr_data, group,
893 "# callfunc: ");
895 } while (fp->fr_next != NULL);
897 if (group == NULL) {
898 while ((g = grtop) != NULL) {
899 printf("# Group %s\n", g->fg_name);
900 printlivelist(out, set, NULL, g->fg_name, comment);
901 grtop = g->fg_next;
902 free(g);
905 free(buf);
909 static void printdeadlist(out, set, fp, group, comment)
910 int out, set;
911 frentry_t *fp;
912 char *group, *comment;
914 frgroup_t *grtop, *grtail, *g;
915 struct frentry fb;
916 char *data;
917 u_32_t type;
918 int n;
920 fb.fr_next = fp;
921 n = 0;
922 grtop = NULL;
923 grtail = NULL;
925 do {
926 fp = fb.fr_next;
927 if (kmemcpy((char *)&fb, (u_long)fb.fr_next,
928 sizeof(fb)) == -1) {
929 perror("kmemcpy");
930 return;
933 data = NULL;
934 type = fb.fr_type & ~FR_T_BUILTIN;
935 if (type == FR_T_IPF || type == FR_T_BPFOPC) {
936 if (fb.fr_dsize) {
937 data = malloc(fb.fr_dsize);
939 if (kmemcpy(data, (u_long)fb.fr_data,
940 fb.fr_dsize) == -1) {
941 perror("kmemcpy");
942 return;
944 fb.fr_data = data;
948 n++;
950 if (opts & (OPT_HITS|OPT_VERBOSE))
951 #ifdef USE_QUAD_T
952 PRINTF("%qu ", (unsigned long long) fb.fr_hits);
953 #else
954 PRINTF("%lu ", fb.fr_hits);
955 #endif
956 if (opts & (OPT_ACCNT|OPT_VERBOSE))
957 #ifdef USE_QUAD_T
958 PRINTF("%qu ", (unsigned long long) fb.fr_bytes);
959 #else
960 PRINTF("%lu ", fb.fr_bytes);
961 #endif
962 if (opts & OPT_SHOWLINENO)
963 PRINTF("@%d ", n);
965 printfr(fp, ioctl);
966 if (opts & OPT_DEBUG) {
967 binprint(fp, sizeof(*fp));
968 if (fb.fr_data != NULL && fb.fr_dsize > 0)
969 binprint(fb.fr_data, fb.fr_dsize);
971 if (data != NULL)
972 free(data);
973 if (fb.fr_grhead[0] != '\0') {
974 g = calloc(1, sizeof(*g));
976 if (g != NULL) {
977 strncpy(g->fg_name, fb.fr_grhead,
978 FR_GROUPLEN);
979 if (grtop == NULL) {
980 grtop = g;
981 grtail = g;
982 } else {
983 grtail->fg_next = g;
984 grtail = g;
988 if (type == FR_T_CALLFUNC) {
989 printdeadlist(out, set, fb.fr_data, group,
990 "# callfunc: ");
992 } while (fb.fr_next != NULL);
994 while ((g = grtop) != NULL) {
995 printdeadlist(out, set, NULL, g->fg_name, comment);
996 grtop = g->fg_next;
997 free(g);
1002 * print out all of the asked for rule sets, using the stats struct as
1003 * the base from which to get the pointers.
1005 static void showlist(fiop)
1006 struct friostat *fiop;
1008 struct frentry *fp = NULL;
1009 int i, set;
1011 set = fiop->f_active;
1012 if (opts & OPT_INACTIVE)
1013 set = 1 - set;
1014 if (opts & OPT_ACCNT) {
1015 #ifdef USE_INET6
1016 if ((use_inet6) && (opts & OPT_OUTQUE)) {
1017 i = F_ACOUT;
1018 fp = (struct frentry *)fiop->f_acctout6[set];
1019 } else if ((use_inet6) && (opts & OPT_INQUE)) {
1020 i = F_ACIN;
1021 fp = (struct frentry *)fiop->f_acctin6[set];
1022 } else
1023 #endif
1024 if (opts & OPT_OUTQUE) {
1025 i = F_ACOUT;
1026 fp = (struct frentry *)fiop->f_acctout[set];
1027 } else if (opts & OPT_INQUE) {
1028 i = F_ACIN;
1029 fp = (struct frentry *)fiop->f_acctin[set];
1030 } else {
1031 FPRINTF(stderr, "No -i or -o given with -a\n");
1032 return;
1034 } else {
1035 #ifdef USE_INET6
1036 if ((use_inet6) && (opts & OPT_OUTQUE)) {
1037 i = F_OUT;
1038 fp = (struct frentry *)fiop->f_fout6[set];
1039 } else if ((use_inet6) && (opts & OPT_INQUE)) {
1040 i = F_IN;
1041 fp = (struct frentry *)fiop->f_fin6[set];
1042 } else
1043 #endif
1044 if (opts & OPT_OUTQUE) {
1045 i = F_OUT;
1046 fp = (struct frentry *)fiop->f_fout[set];
1047 } else if (opts & OPT_INQUE) {
1048 i = F_IN;
1049 fp = (struct frentry *)fiop->f_fin[set];
1050 } else
1051 return;
1053 if (opts & OPT_DEBUG)
1054 FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
1056 if (opts & OPT_DEBUG)
1057 PRINTF("fp %p set %d\n", fp, set);
1058 if (!fp) {
1059 FPRINTF(stderr, "empty list for %s%s\n",
1060 (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]);
1061 return;
1063 if (live_kernel == 1)
1064 printlivelist(i, set, fp, NULL, NULL);
1065 else
1066 printdeadlist(i, set, fp, NULL, NULL);
1071 * Display ipfilter stateful filtering information
1073 static void showipstates(ipsp)
1074 ips_stat_t *ipsp;
1076 u_long minlen, maxlen, totallen, *buckets;
1077 ipftable_t table;
1078 ipfobj_t obj;
1079 int i, sz;
1082 * If a list of states hasn't been asked for, only print out stats
1084 if (!(opts & OPT_SHOWLIST)) {
1086 sz = sizeof(*buckets) * ipsp->iss_statesize;
1087 buckets = (u_long *)malloc(sz);
1089 obj.ipfo_rev = IPFILTER_VERSION;
1090 obj.ipfo_type = IPFOBJ_GTABLE;
1091 obj.ipfo_size = sizeof(table);
1092 obj.ipfo_ptr = &table;
1094 table.ita_type = IPFTABLE_BUCKETS;
1095 table.ita_table = buckets;
1097 if (live_kernel == 1) {
1098 if (ioctl(state_fd, SIOCGTABL, &obj) != 0) {
1099 free(buckets);
1100 return;
1102 } else {
1103 if (kmemcpy((char *)buckets,
1104 (u_long)ipsp->iss_bucketlen, sz)) {
1105 free(buckets);
1106 return;
1110 PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n",
1111 ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp);
1112 PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits,
1113 ipsp->iss_miss);
1114 PRINTF("\t%lu bucket full\n", ipsp->iss_bucketfull);
1115 PRINTF("\t%lu maximum rule references\n", ipsp->iss_maxref);
1116 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu bkts in use\n",
1117 ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse);
1118 PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n",
1119 ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin);
1121 PRINTF("State logging %sabled\n",
1122 state_logging ? "en" : "dis");
1124 PRINTF("\nState table bucket statistics:\n");
1125 PRINTF("\t%lu in use\t\n", ipsp->iss_inuse);
1126 PRINTF("\t%u%% hash efficiency\n", ipsp->iss_active ?
1127 (u_int)(ipsp->iss_inuse * 100 / ipsp->iss_active) : 0);
1129 minlen = ipsp->iss_inuse;
1130 totallen = 0;
1131 maxlen = 0;
1133 for (i = 0; i < ipsp->iss_statesize; i++) {
1134 if (buckets[i] > maxlen)
1135 maxlen = buckets[i];
1136 if (buckets[i] < minlen)
1137 minlen = buckets[i];
1138 totallen += buckets[i];
1141 PRINTF("\t%2.2f%% bucket usage\n\t%lu minimal length\n",
1142 ((float)ipsp->iss_inuse / ipsp->iss_statesize) * 100.0,
1143 minlen);
1144 PRINTF("\t%lu maximal length\n\t%.3f average length\n",
1145 maxlen,
1146 ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse :
1147 0.0);
1149 #define ENTRIES_PER_LINE 5
1151 if (opts & OPT_VERBOSE) {
1152 PRINTF("\nCurrent bucket sizes :\n");
1153 for (i = 0; i < ipsp->iss_statesize; i++) {
1154 if ((i % ENTRIES_PER_LINE) == 0)
1155 PRINTF("\t");
1156 PRINTF("%4d -> %4lu", i, buckets[i]);
1157 if ((i % ENTRIES_PER_LINE) ==
1158 (ENTRIES_PER_LINE - 1))
1159 PRINTF("\n");
1160 else
1161 PRINTF(" ");
1163 PRINTF("\n");
1165 PRINTF("\n");
1167 free(buckets);
1169 if (live_kernel == 1) {
1170 showtqtable_live(state_fd);
1171 } else {
1172 printtqtable(ipsp->iss_tcptab);
1175 return;
1180 * Print out all the state information currently held in the kernel.
1182 while (ipsp->iss_list != NULL) {
1183 ipstate_t ips;
1185 ipsp->iss_list = fetchstate(ipsp->iss_list, &ips);
1187 if (ipsp->iss_list != NULL) {
1188 ipsp->iss_list = ips.is_next;
1189 printstate(&ips, opts, ipsp->iss_ticks);
1195 #ifdef STATETOP
1196 static int handle_resize = 0, handle_break = 0;
1198 static void topipstates(saddr, daddr, sport, dport, protocol, ver,
1199 refreshtime, topclosed)
1200 i6addr_t saddr;
1201 i6addr_t daddr;
1202 int sport;
1203 int dport;
1204 int protocol;
1205 int ver;
1206 int refreshtime;
1207 int topclosed;
1209 char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
1210 int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
1211 int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0;
1212 int len, srclen, dstlen, forward = 1, c = 0;
1213 ips_stat_t ipsst, *ipsstp = &ipsst;
1214 int token_type = IPFGENITER_STATE;
1215 statetop_t *tstable = NULL, *tp;
1216 const char *errstr = "";
1217 ipstate_t ips;
1218 ipfobj_t ipfo;
1219 struct timeval selecttimeout;
1220 char hostnm[HOSTNMLEN];
1221 struct protoent *proto;
1222 fd_set readfd;
1223 time_t t;
1225 /* install signal handlers */
1226 signal(SIGINT, sig_break);
1227 signal(SIGQUIT, sig_break);
1228 signal(SIGTERM, sig_break);
1229 signal(SIGWINCH, sig_resize);
1231 /* init ncurses stuff */
1232 initscr();
1233 cbreak();
1234 noecho();
1235 curs_set(0);
1236 timeout(0);
1237 getmaxyx(stdscr, maxy, maxx);
1239 /* init hostname */
1240 gethostname(hostnm, sizeof(hostnm) - 1);
1241 hostnm[sizeof(hostnm) - 1] = '\0';
1243 /* init ipfobj_t stuff */
1244 bzero((caddr_t)&ipfo, sizeof(ipfo));
1245 ipfo.ipfo_rev = IPFILTER_VERSION;
1246 ipfo.ipfo_type = IPFOBJ_STATESTAT;
1247 ipfo.ipfo_size = sizeof(*ipsstp);
1248 ipfo.ipfo_ptr = (void *)ipsstp;
1250 /* repeat until user aborts */
1251 while ( 1 ) {
1253 /* get state table */
1254 bzero((char *)&ipsst, sizeof(ipsst));
1255 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
1256 errstr = "ioctl(SIOCGETFS)";
1257 ret = -1;
1258 goto out;
1261 /* clear the history */
1262 tsentry = -1;
1264 /* reset max str len */
1265 srclen = dstlen = 0;
1267 /* read the state table and store in tstable */
1268 for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
1270 ipsstp->iss_list = fetchstate(ipsstp->iss_list, &ips);
1271 if (ipsstp->iss_list == NULL)
1272 break;
1274 if (ips.is_v != ver)
1275 continue;
1277 /* check v4 src/dest addresses */
1278 if (ips.is_v == 4) {
1279 if ((saddr.in4.s_addr != INADDR_ANY &&
1280 saddr.in4.s_addr != ips.is_saddr) ||
1281 (daddr.in4.s_addr != INADDR_ANY &&
1282 daddr.in4.s_addr != ips.is_daddr))
1283 continue;
1285 #ifdef USE_INET6
1286 /* check v6 src/dest addresses */
1287 if (ips.is_v == 6) {
1288 if ((IP6_NEQ(&saddr, &in6addr_any) &&
1289 IP6_NEQ(&saddr, &ips.is_src)) ||
1290 (IP6_NEQ(&daddr, &in6addr_any) &&
1291 IP6_NEQ(&daddr, &ips.is_dst)))
1292 continue;
1294 #endif
1295 /* check protocol */
1296 if (protocol > 0 && protocol != ips.is_p)
1297 continue;
1299 /* check ports if protocol is TCP or UDP */
1300 if (((ips.is_p == IPPROTO_TCP) ||
1301 (ips.is_p == IPPROTO_UDP)) &&
1302 (((sport > 0) && (htons(sport) != ips.is_sport)) ||
1303 ((dport > 0) && (htons(dport) != ips.is_dport))))
1304 continue;
1306 /* show closed TCP sessions ? */
1307 if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
1308 (ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
1309 (ips.is_state[1] >= IPF_TCPS_LAST_ACK))
1310 continue;
1313 * if necessary make room for this state
1314 * entry
1316 tsentry++;
1317 if (!maxtsentries || tsentry == maxtsentries) {
1318 maxtsentries += STGROWSIZE;
1319 tstable = realloc(tstable,
1320 maxtsentries * sizeof(statetop_t));
1321 if (tstable == NULL) {
1322 perror("realloc");
1323 exit(-1);
1327 /* get max src/dest address string length */
1328 len = strlen(getip(ips.is_v, &ips.is_src));
1329 if (srclen < len)
1330 srclen = len;
1331 len = strlen(getip(ips.is_v, &ips.is_dst));
1332 if (dstlen < len)
1333 dstlen = len;
1335 /* fill structure */
1336 tp = tstable + tsentry;
1337 tp->st_src = ips.is_src;
1338 tp->st_dst = ips.is_dst;
1339 tp->st_p = ips.is_p;
1340 tp->st_v = ips.is_v;
1341 tp->st_state[0] = ips.is_state[0];
1342 tp->st_state[1] = ips.is_state[1];
1343 if (forward) {
1344 tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
1345 tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
1346 } else {
1347 tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3];
1348 tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3];
1350 tp->st_age = ips.is_die - ipsstp->iss_ticks;
1351 if ((ips.is_p == IPPROTO_TCP) ||
1352 (ips.is_p == IPPROTO_UDP)) {
1353 tp->st_sport = ips.is_sport;
1354 tp->st_dport = ips.is_dport;
1358 (void) ioctl(state_fd, SIOCIPFDELTOK, &token_type);
1361 /* sort the array */
1362 if (tsentry != -1) {
1363 switch (sorting)
1365 case STSORT_PR:
1366 qsort(tstable, tsentry + 1,
1367 sizeof(statetop_t), sort_p);
1368 break;
1369 case STSORT_PKTS:
1370 qsort(tstable, tsentry + 1,
1371 sizeof(statetop_t), sort_pkts);
1372 break;
1373 case STSORT_BYTES:
1374 qsort(tstable, tsentry + 1,
1375 sizeof(statetop_t), sort_bytes);
1376 break;
1377 case STSORT_TTL:
1378 qsort(tstable, tsentry + 1,
1379 sizeof(statetop_t), sort_ttl);
1380 break;
1381 case STSORT_SRCIP:
1382 qsort(tstable, tsentry + 1,
1383 sizeof(statetop_t), sort_srcip);
1384 break;
1385 case STSORT_SRCPT:
1386 qsort(tstable, tsentry +1,
1387 sizeof(statetop_t), sort_srcpt);
1388 break;
1389 case STSORT_DSTIP:
1390 qsort(tstable, tsentry + 1,
1391 sizeof(statetop_t), sort_dstip);
1392 break;
1393 case STSORT_DSTPT:
1394 qsort(tstable, tsentry + 1,
1395 sizeof(statetop_t), sort_dstpt);
1396 break;
1397 default:
1398 break;
1402 /* handle window resizes */
1403 if (handle_resize) {
1404 endwin();
1405 initscr();
1406 cbreak();
1407 noecho();
1408 curs_set(0);
1409 timeout(0);
1410 getmaxyx(stdscr, maxy, maxx);
1411 redraw = 1;
1412 handle_resize = 0;
1415 /* stop program? */
1416 if (handle_break)
1417 break;
1419 /* print title */
1420 erase();
1421 attron(A_BOLD);
1422 winy = 0;
1423 move(winy,0);
1424 sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION);
1425 for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
1426 printw(" ");
1427 printw("%s", str1);
1428 attroff(A_BOLD);
1430 /* just for fun add a clock */
1431 move(winy, maxx - 8);
1432 t = time(NULL);
1433 strftime(str1, 80, "%T", localtime(&t));
1434 printw("%s\n", str1);
1437 * print the display filters, this is placed in the loop,
1438 * because someday I might add code for changing these
1439 * while the programming is running :-)
1441 if (sport >= 0)
1442 sprintf(str1, "%s,%d", getip(ver, &saddr), sport);
1443 else
1444 sprintf(str1, "%s", getip(ver, &saddr));
1446 if (dport >= 0)
1447 sprintf(str2, "%s,%d", getip(ver, &daddr), dport);
1448 else
1449 sprintf(str2, "%s", getip(ver, &daddr));
1451 if (protocol < 0)
1452 strcpy(str3, "any");
1453 else if ((proto = getprotobynumber(protocol)) != NULL)
1454 sprintf(str3, "%s", proto->p_name);
1455 else
1456 sprintf(str3, "%d", protocol);
1458 switch (sorting)
1460 case STSORT_PR:
1461 sprintf(str4, "proto");
1462 break;
1463 case STSORT_PKTS:
1464 sprintf(str4, "# pkts");
1465 break;
1466 case STSORT_BYTES:
1467 sprintf(str4, "# bytes");
1468 break;
1469 case STSORT_TTL:
1470 sprintf(str4, "ttl");
1471 break;
1472 case STSORT_SRCIP:
1473 sprintf(str4, "src ip");
1474 break;
1475 case STSORT_SRCPT:
1476 sprintf(str4, "src port");
1477 break;
1478 case STSORT_DSTIP:
1479 sprintf(str4, "dest ip");
1480 break;
1481 case STSORT_DSTPT:
1482 sprintf(str4, "dest port");
1483 break;
1484 default:
1485 sprintf(str4, "unknown");
1486 break;
1489 if (reverse)
1490 strcat(str4, " (reverse)");
1492 winy += 2;
1493 move(winy,0);
1494 printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
1495 str1, str2, str3, str4);
1498 * For an IPv4 IP address we need at most 15 characters,
1499 * 4 tuples of 3 digits, separated by 3 dots. Enforce this
1500 * length, so the colums do not change positions based
1501 * on the size of the IP address. This length makes the
1502 * output fit in a 80 column terminal.
1503 * We are lacking a good solution for IPv6 addresses (that
1504 * can be longer that 15 characters), so we do not enforce
1505 * a maximum on the IP field size.
1507 if (srclen < 15)
1508 srclen = 15;
1509 if (dstlen < 15)
1510 dstlen = 15;
1512 /* print column description */
1513 winy += 2;
1514 move(winy,0);
1515 attron(A_BOLD);
1516 printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
1517 srclen + 6, "Source IP", dstlen + 6, "Destination IP",
1518 "ST", "PR", "#pkts", "#bytes", "ttl");
1519 attroff(A_BOLD);
1521 /* print all the entries */
1522 tp = tstable;
1523 if (reverse)
1524 tp += tsentry;
1526 if (tsentry > maxy - 6)
1527 tsentry = maxy - 6;
1528 for (i = 0; i <= tsentry; i++) {
1529 /* print src/dest and port */
1530 if ((tp->st_p == IPPROTO_TCP) ||
1531 (tp->st_p == IPPROTO_UDP)) {
1532 sprintf(str1, "%s,%hu",
1533 getip(tp->st_v, &tp->st_src),
1534 ntohs(tp->st_sport));
1535 sprintf(str2, "%s,%hu",
1536 getip(tp->st_v, &tp->st_dst),
1537 ntohs(tp->st_dport));
1538 } else {
1539 sprintf(str1, "%s", getip(tp->st_v,
1540 &tp->st_src));
1541 sprintf(str2, "%s", getip(tp->st_v,
1542 &tp->st_dst));
1544 winy++;
1545 move(winy, 0);
1546 printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
1548 /* print state */
1549 sprintf(str1, "%X/%X", tp->st_state[0],
1550 tp->st_state[1]);
1551 printw(" %3s", str1);
1553 /* print protocol */
1554 proto = getprotobynumber(tp->st_p);
1555 if (proto) {
1556 strncpy(str1, proto->p_name, 4);
1557 str1[4] = '\0';
1558 } else {
1559 sprintf(str1, "%d", tp->st_p);
1561 /* just print icmp for IPv6-ICMP */
1562 if (tp->st_p == IPPROTO_ICMPV6)
1563 strcpy(str1, "icmp");
1564 printw(" %4s", str1);
1566 /* print #pkt/#bytes */
1567 #ifdef USE_QUAD_T
1568 printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
1569 (unsigned long long) tp->st_bytes);
1570 #else
1571 printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
1572 #endif
1573 printw(" %9s", ttl_to_string(tp->st_age));
1575 if (reverse)
1576 tp--;
1577 else
1578 tp++;
1581 /* screen data structure is filled, now update the screen */
1582 if (redraw)
1583 clearok(stdscr,1);
1585 if (refresh() == ERR)
1586 break;
1587 if (redraw) {
1588 clearok(stdscr,0);
1589 redraw = 0;
1592 /* wait for key press or a 1 second time out period */
1593 selecttimeout.tv_sec = refreshtime;
1594 selecttimeout.tv_usec = 0;
1595 FD_ZERO(&readfd);
1596 FD_SET(0, &readfd);
1597 select(1, &readfd, NULL, NULL, &selecttimeout);
1599 /* if key pressed, read all waiting keys */
1600 if (FD_ISSET(0, &readfd)) {
1601 c = wgetch(stdscr);
1602 if (c == ERR)
1603 continue;
1605 if (ISALPHA(c) && ISUPPER(c))
1606 c = TOLOWER(c);
1607 if (c == 'l') {
1608 redraw = 1;
1609 } else if (c == 'q') {
1610 break;
1611 } else if (c == 'r') {
1612 reverse = !reverse;
1613 } else if (c == 'b') {
1614 forward = 0;
1615 } else if (c == 'f') {
1616 forward = 1;
1617 } else if (c == 's') {
1618 if (++sorting > STSORT_MAX)
1619 sorting = 0;
1622 } /* while */
1624 out:
1625 printw("\n");
1626 curs_set(1);
1627 /* nocbreak(); XXX - endwin() should make this redundant */
1628 endwin();
1630 free(tstable);
1631 if (ret != 0)
1632 perror(errstr);
1634 #endif
1638 * Show fragment cache information that's held in the kernel.
1640 static void showfrstates(ifsp, ticks)
1641 ipfrstat_t *ifsp;
1642 u_long ticks;
1644 struct ipfr *ipfrtab[IPFT_SIZE], ifr;
1645 int i;
1648 * print out the numeric statistics
1650 PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n",
1651 ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
1652 PRINTF("\t%lu retrans\n\t%lu too short\n",
1653 ifsp->ifs_retrans0, ifsp->ifs_short);
1654 PRINTF("\t%lu no memory\n\t%lu already exist\n",
1655 ifsp->ifs_nomem, ifsp->ifs_exists);
1656 PRINTF("\t%lu inuse\n", ifsp->ifs_inuse);
1657 PRINTF("\n");
1659 if (live_kernel == 0) {
1660 if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table,
1661 sizeof(ipfrtab)))
1662 return;
1666 * Print out the contents (if any) of the fragment cache table.
1668 if (live_kernel == 1) {
1669 do {
1670 if (fetchfrag(ipf_fd, IPFGENITER_FRAG, &ifr) != 0)
1671 break;
1672 if (ifr.ipfr_ifp == NULL)
1673 break;
1674 ifr.ipfr_ttl -= ticks;
1675 printfraginfo("", &ifr);
1676 } while (1);
1677 } else {
1678 for (i = 0; i < IPFT_SIZE; i++)
1679 while (ipfrtab[i] != NULL) {
1680 if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1681 sizeof(ifr)) == -1)
1682 break;
1683 printfraginfo("", &ifr);
1684 ipfrtab[i] = ifr.ipfr_next;
1688 * Print out the contents (if any) of the NAT fragment cache table.
1691 if (live_kernel == 0) {
1692 if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,
1693 sizeof(ipfrtab)))
1694 return;
1697 if (live_kernel == 1) {
1698 do {
1699 if (fetchfrag(nat_fd, IPFGENITER_NATFRAG, &ifr) != 0)
1700 break;
1701 if (ifr.ipfr_ifp == NULL)
1702 break;
1703 ifr.ipfr_ttl -= ticks;
1704 printfraginfo("NAT: ", &ifr);
1705 } while (1);
1706 } else {
1707 for (i = 0; i < IPFT_SIZE; i++)
1708 while (ipfrtab[i] != NULL) {
1709 if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1710 sizeof(ifr)) == -1)
1711 break;
1712 printfraginfo("NAT: ", &ifr);
1713 ipfrtab[i] = ifr.ipfr_next;
1720 * Show stats on how auth within IPFilter has been used
1722 static void showauthstates(asp)
1723 fr_authstat_t *asp;
1725 frauthent_t *frap, fra;
1726 ipfgeniter_t auth;
1727 ipfobj_t obj;
1729 obj.ipfo_rev = IPFILTER_VERSION;
1730 obj.ipfo_type = IPFOBJ_GENITER;
1731 obj.ipfo_size = sizeof(auth);
1732 obj.ipfo_ptr = &auth;
1734 auth.igi_type = IPFGENITER_AUTH;
1735 auth.igi_nitems = 1;
1736 auth.igi_data = &fra;
1738 #ifdef USE_QUAD_T
1739 printf("Authorisation hits: %qu\tmisses %qu\n",
1740 (unsigned long long) asp->fas_hits,
1741 (unsigned long long) asp->fas_miss);
1742 #else
1743 printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
1744 asp->fas_miss);
1745 #endif
1746 printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
1747 asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
1748 asp->fas_sendok);
1749 printf("queok %ld\nquefail %ld\nexpire %ld\n",
1750 asp->fas_queok, asp->fas_quefail, asp->fas_expire);
1752 frap = asp->fas_faelist;
1753 while (frap) {
1754 if (live_kernel == 1) {
1755 if (ioctl(auth_fd, SIOCGENITER, &obj))
1756 break;
1757 } else {
1758 if (kmemcpy((char *)&fra, (u_long)frap,
1759 sizeof(fra)) == -1)
1760 break;
1762 printf("age %ld\t", fra.fae_age);
1763 printfr(&fra.fae_fr, ioctl);
1764 frap = fra.fae_next;
1770 * Display groups used for each of filter rules, accounting rules and
1771 * authentication, separately.
1773 static void showgroups(fiop)
1774 struct friostat *fiop;
1776 static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
1777 static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH };
1778 frgroup_t *fp, grp;
1779 int on, off, i;
1781 on = fiop->f_active;
1782 off = 1 - on;
1784 for (i = 0; i < 3; i++) {
1785 printf("%s groups (active):\n", gnames[i]);
1786 for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL;
1787 fp = grp.fg_next)
1788 if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1789 break;
1790 else
1791 printf("%s\n", grp.fg_name);
1792 printf("%s groups (inactive):\n", gnames[i]);
1793 for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL;
1794 fp = grp.fg_next)
1795 if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1796 break;
1797 else
1798 printf("%s\n", grp.fg_name);
1802 static void parse_ipportstr(argument, ip, port)
1803 const char *argument;
1804 i6addr_t *ip;
1805 int *port;
1807 char *s, *comma;
1808 int ok = 0;
1810 /* make working copy of argument, Theoretically you must be able
1811 * to write to optarg, but that seems very ugly to me....
1813 s = strdup(argument);
1814 if (s == NULL)
1815 return;
1817 /* get port */
1818 if ((comma = strchr(s, ',')) != NULL) {
1819 if (!strcasecmp(comma + 1, "any")) {
1820 *port = -1;
1821 } else if (!sscanf(comma + 1, "%d", port) ||
1822 (*port < 0) || (*port > 65535)) {
1823 fprintf(stderr, "Invalid port specification in %s\n",
1824 argument);
1825 free(s);
1826 exit(-2);
1828 *comma = '\0';
1832 /* get ip address */
1833 if (!strcasecmp(s, "any")) {
1834 ip->in4.s_addr = INADDR_ANY;
1835 ok = 1;
1836 #ifdef USE_INET6
1837 ip->in6 = in6addr_any;
1838 } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) {
1839 ok = 1;
1840 #endif
1841 } else if (inet_aton(s, &ip->in4))
1842 ok = 1;
1844 if (ok == 0) {
1845 fprintf(stderr, "Invalid IP address: %s\n", s);
1846 free(s);
1847 exit(-2);
1850 /* free allocated memory */
1851 free(s);
1855 #ifdef STATETOP
1856 static void sig_resize(s)
1857 int s;
1859 handle_resize = 1;
1862 static void sig_break(s)
1863 int s;
1865 handle_break = 1;
1868 static char *getip(v, addr)
1869 int v;
1870 i6addr_t *addr;
1872 #ifdef USE_INET6
1873 static char hostbuf[MAXHOSTNAMELEN+1];
1874 #endif
1876 if (v == 4)
1877 return inet_ntoa(addr->in4);
1879 #ifdef USE_INET6
1880 (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1);
1881 hostbuf[MAXHOSTNAMELEN] = '\0';
1882 return hostbuf;
1883 #else
1884 return "IPv6";
1885 #endif
1889 static char *ttl_to_string(ttl)
1890 long int ttl;
1892 static char ttlbuf[STSTRSIZE];
1893 int hours, minutes, seconds;
1895 /* ttl is in half seconds */
1896 ttl /= 2;
1898 hours = ttl / 3600;
1899 ttl = ttl % 3600;
1900 minutes = ttl / 60;
1901 seconds = ttl % 60;
1903 if (hours > 0)
1904 sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds);
1905 else
1906 sprintf(ttlbuf, "%2d:%02d", minutes, seconds);
1907 return ttlbuf;
1911 static int sort_pkts(a, b)
1912 const void *a;
1913 const void *b;
1916 register const statetop_t *ap = a;
1917 register const statetop_t *bp = b;
1919 if (ap->st_pkts == bp->st_pkts)
1920 return 0;
1921 else if (ap->st_pkts < bp->st_pkts)
1922 return 1;
1923 return -1;
1927 static int sort_bytes(a, b)
1928 const void *a;
1929 const void *b;
1931 register const statetop_t *ap = a;
1932 register const statetop_t *bp = b;
1934 if (ap->st_bytes == bp->st_bytes)
1935 return 0;
1936 else if (ap->st_bytes < bp->st_bytes)
1937 return 1;
1938 return -1;
1942 static int sort_p(a, b)
1943 const void *a;
1944 const void *b;
1946 register const statetop_t *ap = a;
1947 register const statetop_t *bp = b;
1949 if (ap->st_p == bp->st_p)
1950 return 0;
1951 else if (ap->st_p < bp->st_p)
1952 return 1;
1953 return -1;
1957 static int sort_ttl(a, b)
1958 const void *a;
1959 const void *b;
1961 register const statetop_t *ap = a;
1962 register const statetop_t *bp = b;
1964 if (ap->st_age == bp->st_age)
1965 return 0;
1966 else if (ap->st_age < bp->st_age)
1967 return 1;
1968 return -1;
1971 static int sort_srcip(a, b)
1972 const void *a;
1973 const void *b;
1975 register const statetop_t *ap = a;
1976 register const statetop_t *bp = b;
1978 #ifdef USE_INET6
1979 if (use_inet6) {
1980 if (IP6_EQ(&ap->st_src, &bp->st_src))
1981 return 0;
1982 else if (IP6_GT(&ap->st_src, &bp->st_src))
1983 return 1;
1984 } else
1985 #endif
1987 if (ntohl(ap->st_src.in4.s_addr) ==
1988 ntohl(bp->st_src.in4.s_addr))
1989 return 0;
1990 else if (ntohl(ap->st_src.in4.s_addr) >
1991 ntohl(bp->st_src.in4.s_addr))
1992 return 1;
1994 return -1;
1997 static int sort_srcpt(a, b)
1998 const void *a;
1999 const void *b;
2001 register const statetop_t *ap = a;
2002 register const statetop_t *bp = b;
2004 if (htons(ap->st_sport) == htons(bp->st_sport))
2005 return 0;
2006 else if (htons(ap->st_sport) > htons(bp->st_sport))
2007 return 1;
2008 return -1;
2011 static int sort_dstip(a, b)
2012 const void *a;
2013 const void *b;
2015 register const statetop_t *ap = a;
2016 register const statetop_t *bp = b;
2018 #ifdef USE_INET6
2019 if (use_inet6) {
2020 if (IP6_EQ(&ap->st_dst, &bp->st_dst))
2021 return 0;
2022 else if (IP6_GT(&ap->st_dst, &bp->st_dst))
2023 return 1;
2024 } else
2025 #endif
2027 if (ntohl(ap->st_dst.in4.s_addr) ==
2028 ntohl(bp->st_dst.in4.s_addr))
2029 return 0;
2030 else if (ntohl(ap->st_dst.in4.s_addr) >
2031 ntohl(bp->st_dst.in4.s_addr))
2032 return 1;
2034 return -1;
2037 static int sort_dstpt(a, b)
2038 const void *a;
2039 const void *b;
2041 register const statetop_t *ap = a;
2042 register const statetop_t *bp = b;
2044 if (htons(ap->st_dport) == htons(bp->st_dport))
2045 return 0;
2046 else if (htons(ap->st_dport) > htons(bp->st_dport))
2047 return 1;
2048 return -1;
2051 #endif
2054 ipstate_t *fetchstate(src, dst)
2055 ipstate_t *src, *dst;
2057 if (live_kernel == 1) {
2058 ipfgeniter_t state;
2059 ipfobj_t obj;
2061 obj.ipfo_rev = IPFILTER_VERSION;
2062 obj.ipfo_type = IPFOBJ_GENITER;
2063 obj.ipfo_size = sizeof(state);
2064 obj.ipfo_ptr = &state;
2066 state.igi_type = IPFGENITER_STATE;
2067 state.igi_nitems = 1;
2068 state.igi_data = dst;
2070 if (ioctl(state_fd, SIOCGENITER, &obj) != 0)
2071 return NULL;
2072 } else {
2073 if (kmemcpy((char *)dst, (u_long)src, sizeof(*dst)))
2074 return NULL;
2076 return dst;
2080 static int fetchfrag(fd, type, frp)
2081 int fd, type;
2082 ipfr_t *frp;
2084 ipfgeniter_t frag;
2085 ipfobj_t obj;
2087 obj.ipfo_rev = IPFILTER_VERSION;
2088 obj.ipfo_type = IPFOBJ_GENITER;
2089 obj.ipfo_size = sizeof(frag);
2090 obj.ipfo_ptr = &frag;
2092 frag.igi_type = type;
2093 frag.igi_nitems = 1;
2094 frag.igi_data = frp;
2096 if (ioctl(fd, SIOCGENITER, &obj))
2097 return EFAULT;
2098 return 0;
2102 static void showtqtable_live(fd)
2103 int fd;
2105 ipftq_t table[IPF_TCP_NSTATES];
2106 ipfobj_t obj;
2108 bzero((char *)&obj, sizeof(obj));
2109 obj.ipfo_rev = IPFILTER_VERSION;
2110 obj.ipfo_size = sizeof(table);
2111 obj.ipfo_ptr = (void *)table;
2112 obj.ipfo_type = IPFOBJ_STATETQTAB;
2114 if (ioctl(fd, SIOCGTQTAB, &obj) == 0) {
2115 printtqtable(table);