]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/tools/ipfstat.c
This commit was generated by cvs2svn to compensate for changes in r151937,
[FreeBSD/FreeBSD.git] / contrib / ipfilter / tools / ipfstat.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 1993-2001, 2003 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #ifdef __FreeBSD__
9 # ifndef __FreeBSD_cc_version
10 #  include <osreldate.h>
11 # else
12 #  if __FreeBSD_cc_version < 430000
13 #   include <osreldate.h>
14 #  endif
15 # endif
16 #endif
17 #include <sys/ioctl.h>
18 #include <fcntl.h>
19 #ifdef linux
20 # include <linux/a.out.h>
21 #else
22 # include <nlist.h>
23 #endif
24 #include <ctype.h>
25 #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
26 # include <stddef.h>
27 #endif
28 #include "ipf.h"
29 #include "netinet/ipl.h"
30 #if defined(STATETOP)
31 # if defined(_BSDI_VERSION)
32 #  undef STATETOP
33 # endif
34 # if defined(__FreeBSD__) && \
35      (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000))
36 #  undef STATETOP
37 # endif
38 # if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105000000)
39 #  undef STATETOP
40 # endif
41 # if defined(sun)
42 #  if defined(__svr4__) || defined(__SVR4)
43 #   include <sys/select.h>
44 #  else
45 #   undef STATETOP      /* NOT supported on SunOS4 */
46 #  endif
47 # endif
48 #endif
49 #if defined(STATETOP) && !defined(linux)
50 # include <netinet/ip_var.h>
51 # include <netinet/tcp_fsm.h>
52 #endif
53 #ifdef STATETOP
54 # include <ctype.h>
55 # include <signal.h>
56 # if SOLARIS || defined(__NetBSD__) || defined(_BSDI_VERSION) || \
57      defined(__sgi)
58 #  ifdef ERR
59 #   undef ERR
60 #  endif
61 #  include <curses.h>
62 # else /* SOLARIS */
63 #  include <ncurses.h>
64 # endif /* SOLARIS */
65 #endif /* STATETOP */
66 #include "kmem.h"
67 #if defined(__NetBSD__) || (__OpenBSD__)
68 # include <paths.h>
69 #endif
70
71 #if !defined(lint)
72 static const char sccsid[] = "@(#)fils.c        1.21 4/20/96 (C) 1993-2000 Darren Reed";
73 static const char rcsid[] = "@(#)Id: ipfstat.c,v 1.44.2.11 2005/03/30 14:09:57 darrenr Exp";
74 #endif
75
76 #ifdef __hpux
77 # define        nlist   nlist64
78 #endif
79
80 extern  char    *optarg;
81 extern  int     optind;
82 extern  int     opterr;
83
84 #define PRINTF  (void)printf
85 #define FPRINTF (void)fprintf
86 #define F_IN    0
87 #define F_OUT   1
88 #define F_ACIN  2
89 #define F_ACOUT 3
90 static  char    *filters[4] = { "ipfilter(in)", "ipfilter(out)",
91                                 "ipacct(in)", "ipacct(out)" };
92 static  int     state_logging = -1;
93
94 int     opts = 0;
95 int     use_inet6 = 0;
96 int     live_kernel = 1;
97 int     state_fd = -1;
98 int     ipf_fd = -1;
99
100 #ifdef STATETOP
101 #define STSTRSIZE       80
102 #define STGROWSIZE      16
103 #define HOSTNMLEN       40
104
105 #define STSORT_PR       0
106 #define STSORT_PKTS     1
107 #define STSORT_BYTES    2
108 #define STSORT_TTL      3
109 #define STSORT_SRCIP    4
110 #define STSORT_SRCPT    5
111 #define STSORT_DSTIP    6
112 #define STSORT_DSTPT    7
113 #define STSORT_MAX      STSORT_DSTPT
114 #define STSORT_DEFAULT  STSORT_BYTES
115
116
117 typedef struct statetop {
118         i6addr_t        st_src;
119         i6addr_t        st_dst;
120         u_short         st_sport;
121         u_short         st_dport;
122         u_char          st_p;
123         u_char          st_v;
124         u_char          st_state[2];
125         U_QUAD_T        st_pkts;
126         U_QUAD_T        st_bytes;
127         u_long          st_age;
128 } statetop_t;
129 #endif
130
131 int             main __P((int, char *[]));
132
133 static  void    showstats __P((friostat_t *, u_32_t));
134 static  void    showfrstates __P((ipfrstat_t *));
135 static  void    showlist __P((friostat_t *));
136 static  void    showipstates __P((ips_stat_t *));
137 static  void    showauthstates __P((fr_authstat_t *));
138 static  void    showgroups __P((friostat_t *));
139 static  void    usage __P((char *));
140 static  void    printlist __P((frentry_t *, char *));
141 static  void    parse_ipportstr __P((const char *, i6addr_t *, int *));
142 static  void    ipfstate_live __P((char *, friostat_t **, ips_stat_t **,
143                                    ipfrstat_t **, fr_authstat_t **, u_32_t *));
144 static  void    ipfstate_dead __P((char *, friostat_t **, ips_stat_t **,
145                                    ipfrstat_t **, fr_authstat_t **, u_32_t *));
146 #ifdef STATETOP
147 static  void    topipstates __P((i6addr_t, i6addr_t, int, int, int,
148                                  int, int, int));
149 static  void    sig_break __P((int));
150 static  void    sig_resize __P((int));
151 static  char    *getip __P((int, i6addr_t *));
152 static  char    *ttl_to_string __P((long));
153 static  int     sort_p __P((const void *, const void *));
154 static  int     sort_pkts __P((const void *, const void *));
155 static  int     sort_bytes __P((const void *, const void *));
156 static  int     sort_ttl __P((const void *, const void *));
157 static  int     sort_srcip __P((const void *, const void *));
158 static  int     sort_srcpt __P((const void *, const void *));
159 static  int     sort_dstip __P((const void *, const void *));
160 static  int     sort_dstpt __P((const void *, const void *));
161 #endif
162
163
164 static void usage(name)
165 char *name;
166 {
167 #ifdef  USE_INET6
168         fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name);
169 #else
170         fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name);
171 #endif
172         fprintf(stderr, "       %s [-M corefile] [-N symbol-list]\n", name);
173 #ifdef  USE_INET6
174         fprintf(stderr, "       %s -t [-6C] ", name);
175 #else
176         fprintf(stderr, "       %s -t [-C] ", name);
177 #endif
178         fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n");
179         exit(1);
180 }
181
182
183 int main(argc,argv)
184 int argc;
185 char *argv[];
186 {
187         fr_authstat_t   frauthst;
188         fr_authstat_t   *frauthstp = &frauthst;
189         friostat_t fio;
190         friostat_t *fiop = &fio;
191         ips_stat_t ipsst;
192         ips_stat_t *ipsstp = &ipsst;
193         ipfrstat_t ifrst;
194         ipfrstat_t *ifrstp = &ifrst;
195         char    *device = IPL_NAME, *memf = NULL;
196         char    *options, *kern = NULL;
197         int     c, myoptind;
198
199         int protocol = -1;              /* -1 = wild card for any protocol */
200         int refreshtime = 1;            /* default update time */
201         int sport = -1;                 /* -1 = wild card for any source port */
202         int dport = -1;                 /* -1 = wild card for any dest port */
203         int topclosed = 0;              /* do not show closed tcp sessions */
204         i6addr_t saddr, daddr;
205         u_32_t frf;
206
207 #ifdef  USE_INET6
208         options = "6aACdfghIilnostvD:M:N:P:RS:T:";
209 #else
210         options = "aACdfghIilnostvD:M:N:P:RS:T:";
211 #endif
212
213         saddr.in4.s_addr = INADDR_ANY;  /* default any v4 source addr */
214         daddr.in4.s_addr = INADDR_ANY;  /* default any v4 dest addr */
215 #ifdef  USE_INET6
216         saddr.in6 = in6addr_any;        /* default any v6 source addr */
217         daddr.in6 = in6addr_any;        /* default any v6 dest addr */
218 #endif
219
220         /* Don't warn about invalid flags when we run getopt for the 1st time */
221         opterr = 0;
222
223         /*
224          * Parse these two arguments now lest there be any buffer overflows
225          * in the parsing of the rest.
226          */
227         myoptind = optind;
228         while ((c = getopt(argc, argv, options)) != -1) {
229                 switch (c)
230                 {
231                 case 'M' :
232                         memf = optarg;
233                         live_kernel = 0;
234                         break;
235                 case 'N' :
236                         kern = optarg;
237                         live_kernel = 0;
238                         break;
239                 }
240         }
241         optind = myoptind;
242
243         if (live_kernel == 1) {
244                 if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) {
245                         perror("open(IPSTATE_NAME)");
246                         exit(-1);
247                 }
248                 if ((ipf_fd = open(device, O_RDONLY)) == -1) {
249                         fprintf(stderr, "open(%s)", device);
250                         perror("");
251                         exit(-1);
252                 }
253         }
254
255         if (kern != NULL || memf != NULL) {
256                 (void)setgid(getgid());
257                 (void)setuid(getuid());
258         }
259
260         if (live_kernel == 1)
261                 (void) checkrev(device);
262         if (openkmem(kern, memf) == -1)
263                 exit(-1);
264
265         (void)setgid(getgid());
266         (void)setuid(getuid());
267
268         opterr = 1;
269
270         while ((c = getopt(argc, argv, options)) != -1)
271         {
272                 switch (c)
273                 {
274 #ifdef  USE_INET6
275                 case '6' :
276                         use_inet6 = 1;
277                         break;
278 #endif
279                 case 'a' :
280                         opts |= OPT_ACCNT|OPT_SHOWLIST;
281                         break;
282                 case 'A' :
283                         opts |= OPT_AUTHSTATS;
284                         break;
285                 case 'C' :
286                         topclosed = 1;
287                         break;
288                 case 'd' :
289                         opts |= OPT_DEBUG;
290                         break;
291                 case 'D' :
292                         parse_ipportstr(optarg, &daddr, &dport);
293                         break;
294                 case 'f' :
295                         opts |= OPT_FRSTATES;
296                         break;
297                 case 'g' :
298                         opts |= OPT_GROUPS;
299                         break;
300                 case 'h' :
301                         opts |= OPT_HITS;
302                         break;
303                 case 'i' :
304                         opts |= OPT_INQUE|OPT_SHOWLIST;
305                         break;
306                 case 'I' :
307                         opts |= OPT_INACTIVE;
308                         break;
309                 case 'l' :
310                         opts |= OPT_SHOWLIST;
311                         break;
312                 case 'M' :
313                         break;
314                 case 'N' :
315                         break;
316                 case 'n' :
317                         opts |= OPT_SHOWLINENO;
318                         break;
319                 case 'o' :
320                         opts |= OPT_OUTQUE|OPT_SHOWLIST;
321                         break;
322                 case 'P' :
323                         protocol = getproto(optarg);
324                         if (protocol == -1) {
325                                 fprintf(stderr, "%s: Invalid protocol: %s\n",
326                                         argv[0], optarg);
327                                 exit(-2);
328                         }
329                         break;
330                 case 'R' :
331                         opts |= OPT_NORESOLVE;
332                         break;
333                 case 's' :
334                         opts |= OPT_IPSTATES;
335                         break;
336                 case 'S' :
337                         parse_ipportstr(optarg, &saddr, &sport);
338                         break;
339                 case 't' :
340 #ifdef STATETOP
341                         opts |= OPT_STATETOP;
342                         break;
343 #else
344                         fprintf(stderr,
345                                 "%s: state top facility not compiled in\n",
346                                 argv[0]);
347                         exit(-2);
348 #endif
349                 case 'T' :
350                         if (!sscanf(optarg, "%d", &refreshtime) ||
351                                     (refreshtime <= 0)) {
352                                 fprintf(stderr,
353                                         "%s: Invalid refreshtime < 1 : %s\n",
354                                         argv[0], optarg);
355                                 exit(-2);
356                         }
357                         break;
358                 case 'v' :
359                         opts |= OPT_VERBOSE;
360                         break;
361                 default :
362                         usage(argv[0]);
363                         break;
364                 }
365         }
366
367         if (live_kernel == 1) {
368                 bzero((char *)&fio, sizeof(fio));
369                 bzero((char *)&ipsst, sizeof(ipsst));
370                 bzero((char *)&ifrst, sizeof(ifrst));
371
372                 ipfstate_live(device, &fiop, &ipsstp, &ifrstp,
373                               &frauthstp, &frf);
374         } else
375                 ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf);
376
377         if (opts & OPT_IPSTATES) {
378                 showipstates(ipsstp);
379         } else if (opts & OPT_SHOWLIST) {
380                 showlist(fiop);
381                 if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){
382                         opts &= ~OPT_OUTQUE;
383                         showlist(fiop);
384                 }
385         } else if (opts & OPT_FRSTATES)
386                 showfrstates(ifrstp);
387 #ifdef STATETOP
388         else if (opts & OPT_STATETOP)
389                 topipstates(saddr, daddr, sport, dport, protocol,
390                             use_inet6 ? 6 : 4, refreshtime, topclosed);
391 #endif
392         else if (opts & OPT_AUTHSTATS)
393                 showauthstates(frauthstp);
394         else if (opts & OPT_GROUPS)
395                 showgroups(fiop);
396         else
397                 showstats(fiop, frf);
398
399         return 0;
400 }
401
402
403 /*
404  * Fill in the stats structures from the live kernel, using a combination
405  * of ioctl's and copying directly from kernel memory.
406  */
407 static void ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
408 char *device;
409 friostat_t **fiopp;
410 ips_stat_t **ipsstpp;
411 ipfrstat_t **ifrstpp;
412 fr_authstat_t **frauthstpp;
413 u_32_t *frfp;
414 {
415         ipfobj_t ipfo;
416
417         if (checkrev(device) == -1) {
418                 fprintf(stderr, "User/kernel version check failed\n");
419                 exit(1);
420         }
421
422         if ((opts & OPT_AUTHSTATS) == 0) {
423                 bzero((caddr_t)&ipfo, sizeof(ipfo));
424                 ipfo.ipfo_rev = IPFILTER_VERSION;
425                 ipfo.ipfo_size = sizeof(friostat_t);
426                 ipfo.ipfo_ptr = (void *)*fiopp;
427                 ipfo.ipfo_type = IPFOBJ_IPFSTAT;
428
429                 if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) {
430                         perror("ioctl(ipf:SIOCGETFS)");
431                         exit(-1);
432                 }
433
434                 if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1)
435                         perror("ioctl(SIOCGETFF)");
436         }
437
438         if ((opts & OPT_IPSTATES) != 0) {
439
440                 bzero((caddr_t)&ipfo, sizeof(ipfo));
441                 ipfo.ipfo_rev = IPFILTER_VERSION;
442                 ipfo.ipfo_size = sizeof(ips_stat_t);
443                 ipfo.ipfo_ptr = (void *)*ipsstpp;
444                 ipfo.ipfo_type = IPFOBJ_STATESTAT;
445
446                 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
447                         perror("ioctl(state:SIOCGETFS)");
448                         exit(-1);
449                 }
450                 if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) {
451                         perror("ioctl(state:SIOCGETLG)");
452                         exit(-1);
453                 }
454         }
455
456         if ((opts & OPT_FRSTATES) != 0) {
457                 bzero((caddr_t)&ipfo, sizeof(ipfo));
458                 ipfo.ipfo_rev = IPFILTER_VERSION;
459                 ipfo.ipfo_size = sizeof(ipfrstat_t);
460                 ipfo.ipfo_ptr = (void *)*ifrstpp;
461                 ipfo.ipfo_type = IPFOBJ_FRAGSTAT;
462         
463                 if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) {
464                         perror("ioctl(SIOCGFRST)");
465                         exit(-1);
466                 }
467         }
468
469         if (opts & OPT_VERBOSE)
470                 PRINTF("opts %#x name %s\n", opts, device);
471
472         if ((opts & OPT_AUTHSTATS) != 0) {
473                 if (ipf_fd >= 0) {
474                         close(ipf_fd);
475                         ipf_fd = -1;
476                 }
477                 device = IPAUTH_NAME;
478                 if ((ipf_fd = open(device, O_RDONLY)) == -1) {
479                         perror("open");
480                         exit(-1);
481                 }
482
483                 bzero((caddr_t)&ipfo, sizeof(ipfo));
484                 ipfo.ipfo_rev = IPFILTER_VERSION;
485                 ipfo.ipfo_size = sizeof(fr_authstat_t);
486                 ipfo.ipfo_ptr = (void *)*frauthstpp;
487                 ipfo.ipfo_type = IPFOBJ_AUTHSTAT;
488
489                 if (ioctl(ipf_fd, SIOCATHST, &ipfo) == -1) {
490                         perror("ioctl(SIOCATHST)");
491                         exit(-1);
492                 }
493         }
494 }
495
496
497 /*
498  * Build up the stats structures from data held in the "core" memory.
499  * This is mainly useful when looking at data in crash dumps and ioctl's
500  * just won't work any more.
501  */
502 static void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
503 char *kernel;
504 friostat_t **fiopp;
505 ips_stat_t **ipsstpp;
506 ipfrstat_t **ifrstpp;
507 fr_authstat_t **frauthstpp;
508 u_32_t *frfp;
509 {
510         static fr_authstat_t frauthst, *frauthstp;
511         static ips_stat_t ipsst, *ipsstp;
512         static ipfrstat_t ifrst, *ifrstp;
513         static friostat_t fio, *fiop;
514         int temp;
515
516         void *rules[2][2];
517         struct nlist deadlist[43] = {
518                 { "fr_authstats" },             /* 0 */
519                 { "fae_list" },
520                 { "ipauth" },
521                 { "fr_authlist" },
522                 { "fr_authstart" },
523                 { "fr_authend" },               /* 5 */
524                 { "fr_authnext" },
525                 { "fr_auth" },
526                 { "fr_authused" },
527                 { "fr_authsize" },
528                 { "fr_defaultauthage" },        /* 10 */
529                 { "fr_authpkts" },
530                 { "fr_auth_lock" },
531                 { "frstats" },
532                 { "ips_stats" },
533                 { "ips_num" },                  /* 15 */
534                 { "ips_wild" },
535                 { "ips_list" },
536                 { "ips_table" },
537                 { "fr_statemax" },
538                 { "fr_statesize" },             /* 20 */
539                 { "fr_state_doflush" },
540                 { "fr_state_lock" },
541                 { "ipfr_heads" },
542                 { "ipfr_nattab" },
543                 { "ipfr_stats" },               /* 25 */
544                 { "ipfr_inuse" },
545                 { "fr_ipfrttl" },
546                 { "fr_frag_lock" },
547                 { "ipfr_timer_id" },
548                 { "fr_nat_lock" },              /* 30 */
549                 { "ipfilter" },
550                 { "ipfilter6" },
551                 { "ipacct" },
552                 { "ipacct6" },
553                 { "ipl_frouteok" },             /* 35 */
554                 { "fr_running" },
555                 { "ipfgroups" },
556                 { "fr_active" },
557                 { "fr_pass" },
558                 { "fr_flags" },                 /* 40 */
559                 { "ipstate_logging" },
560                 { NULL }
561         };
562
563
564         frauthstp = &frauthst;
565         ipsstp = &ipsst;
566         ifrstp = &ifrst;
567         fiop = &fio;
568
569         *frfp = 0;
570         *fiopp = fiop;
571         *ipsstpp = ipsstp;
572         *ifrstpp = ifrstp;
573         *frauthstpp = frauthstp;
574
575         bzero((char *)fiop, sizeof(*fiop));
576         bzero((char *)ipsstp, sizeof(*ipsstp));
577         bzero((char *)ifrstp, sizeof(*ifrstp));
578         bzero((char *)frauthstp, sizeof(*frauthstp));
579
580         if (nlist(kernel, deadlist) == -1) {
581                 fprintf(stderr, "nlist error\n");
582                 return;
583         }
584
585         /*
586          * This is for SIOCGETFF.
587          */
588         kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp));
589
590         /*
591          * f_locks is a combination of the lock variable from each part of
592          * ipfilter (state, auth, nat, fragments).
593          */
594         kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop));
595         kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value,
596                 sizeof(fiop->f_locks[0]));
597         kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value,
598                 sizeof(fiop->f_locks[1]));
599         kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value,
600                 sizeof(fiop->f_locks[2]));
601         kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value,
602                 sizeof(fiop->f_locks[3]));
603
604         /*
605          * Get pointers to each list of rules (active, inactive, in, out)
606          */
607         kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules));
608         fiop->f_fin[0] = rules[0][0];
609         fiop->f_fin[1] = rules[0][1];
610         fiop->f_fout[0] = rules[1][0];
611         fiop->f_fout[1] = rules[1][1];
612
613         /*
614          * Same for IPv6, except make them null if support for it is not
615          * being compiled in.
616          */
617 #ifdef  USE_INET6
618         kmemcpy((char *)&rules, (u_long)deadlist[32].n_value, sizeof(rules));
619         fiop->f_fin6[0] = rules[0][0];
620         fiop->f_fin6[1] = rules[0][1];
621         fiop->f_fout6[0] = rules[1][0];
622         fiop->f_fout6[1] = rules[1][1];
623 #else
624         fiop->f_fin6[0] = NULL;
625         fiop->f_fin6[1] = NULL;
626         fiop->f_fout6[0] = NULL;
627         fiop->f_fout6[1] = NULL;
628 #endif
629
630         /*
631          * Now get accounting rules pointers.
632          */
633         kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules));
634         fiop->f_acctin[0] = rules[0][0];
635         fiop->f_acctin[1] = rules[0][1];
636         fiop->f_acctout[0] = rules[1][0];
637         fiop->f_acctout[1] = rules[1][1];
638
639 #ifdef  USE_INET6
640         kmemcpy((char *)&rules, (u_long)deadlist[34].n_value, sizeof(rules));
641         fiop->f_acctin6[0] = rules[0][0];
642         fiop->f_acctin6[1] = rules[0][1];
643         fiop->f_acctout6[0] = rules[1][0];
644         fiop->f_acctout6[1] = rules[1][1];
645 #else
646         fiop->f_acctin6[0] = NULL;
647         fiop->f_acctin6[1] = NULL;
648         fiop->f_acctout6[0] = NULL;
649         fiop->f_acctout6[1] = NULL;
650 #endif
651
652         /*
653          * A collection of "global" variables used inside the kernel which
654          * are all collected in friostat_t via ioctl.
655          */
656         kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[35].n_value,
657                 sizeof(fiop->f_froute));
658         kmemcpy((char *)&fiop->f_running, (u_long)deadlist[36].n_value,
659                 sizeof(fiop->f_running));
660         kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[37].n_value,
661                 sizeof(fiop->f_groups));
662         kmemcpy((char *)&fiop->f_active, (u_long)deadlist[38].n_value,
663                 sizeof(fiop->f_active));
664         kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[39].n_value,
665                 sizeof(fiop->f_defpass));
666
667         /*
668          * Build up the state information stats structure.
669          */
670         kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp));
671         kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp));
672         ipsstp->iss_active = temp;
673         ipsstp->iss_table = (void *)deadlist[18].n_value;
674         ipsstp->iss_list = (void *)deadlist[17].n_value;
675
676         /*
677          * Build up the authentiation information stats structure.
678          */
679         kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value,
680                 sizeof(*frauthstp));
681         frauthstp->fas_faelist = (void *)deadlist[1].n_value;
682
683         /*
684          * Build up the fragment information stats structure.
685          */
686         kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value,
687                 sizeof(*ifrstp));
688         ifrstp->ifs_table = (void *)deadlist[23].n_value;
689         ifrstp->ifs_nattab = (void *)deadlist[24].n_value;
690         kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value,
691                 sizeof(ifrstp->ifs_inuse));
692
693         /*
694          * Get logging on/off switches
695          */
696         kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value,
697                 sizeof(state_logging));
698 }
699
700
701 /*
702  * Display the kernel stats for packets blocked and passed and other
703  * associated running totals which are kept.
704  */
705 static  void    showstats(fp, frf)
706 struct  friostat        *fp;
707 u_32_t frf;
708 {
709
710         PRINTF("bad packets:\t\tin %lu\tout %lu\n",
711                         fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
712 #ifdef  USE_INET6
713         PRINTF(" IPv6 packets:\t\tin %lu out %lu\n",
714                         fp->f_st[0].fr_ipv6, fp->f_st[1].fr_ipv6);
715 #endif
716         PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
717                         fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
718                         fp->f_st[0].fr_nom);
719         PRINTF(" counted %lu short %lu\n",
720                         fp->f_st[0].fr_acct, fp->f_st[0].fr_short);
721         PRINTF("output packets:\t\tblocked %lu passed %lu nomatch %lu",
722                         fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
723                         fp->f_st[1].fr_nom);
724         PRINTF(" counted %lu short %lu\n",
725                         fp->f_st[1].fr_acct, fp->f_st[1].fr_short);
726         PRINTF(" input packets logged:\tblocked %lu passed %lu\n",
727                         fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
728         PRINTF("output packets logged:\tblocked %lu passed %lu\n",
729                         fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
730         PRINTF(" packets logged:\tinput %lu output %lu\n",
731                         fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl);
732         PRINTF(" log failures:\t\tinput %lu output %lu\n",
733                         fp->f_st[0].fr_skip, fp->f_st[1].fr_skip);
734         PRINTF("fragment state(in):\tkept %lu\tlost %lu\tnot fragmented %lu\n",
735                         fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr,
736                         fp->f_st[0].fr_cfr);
737         PRINTF("fragment state(out):\tkept %lu\tlost %lu\tnot fragmented %lu\n",
738                         fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr,
739                         fp->f_st[0].fr_cfr);
740         PRINTF("packet state(in):\tkept %lu\tlost %lu\n",
741                         fp->f_st[0].fr_ads, fp->f_st[0].fr_bads);
742         PRINTF("packet state(out):\tkept %lu\tlost %lu\n",
743                         fp->f_st[1].fr_ads, fp->f_st[1].fr_bads);
744         PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n",
745                         fp->f_st[0].fr_ret, fp->f_st[1].fr_ret);
746         PRINTF("Invalid source(in):\t%lu\n", fp->f_st[0].fr_badsrc);
747         PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n",
748                         fp->f_st[0].fr_chit, fp->f_st[1].fr_chit);
749         PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n",
750                         fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]);
751         PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n",
752                         fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]);
753         PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n",
754                         fp->f_froute[0], fp->f_froute[1]);
755         PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n",
756                         fp->f_st[0].fr_tcpbad, fp->f_st[1].fr_tcpbad);
757         PRINTF("IPF Ticks:\t%lu\n", fp->f_ticks);
758
759         PRINTF("Packet log flags set: (%#x)\n", frf);
760         if (frf & FF_LOGPASS)
761                 PRINTF("\tpackets passed through filter\n");
762         if (frf & FF_LOGBLOCK)
763                 PRINTF("\tpackets blocked by filter\n");
764         if (frf & FF_LOGNOMATCH)
765                 PRINTF("\tpackets not matched by filter\n");
766         if (!frf)
767                 PRINTF("\tnone\n");
768 }
769
770
771 /*
772  * Print out a list of rules from the kernel, starting at the one passed.
773  */
774 static void printlist(fp, comment)
775 frentry_t *fp;
776 char *comment;
777 {
778         struct  frentry fb, *fg;
779         char    *data;
780         u_32_t  type;
781         int     n;
782
783         for (n = 1; fp; n++) {
784                 if (kmemcpy((char *)&fb, (u_long)fp, sizeof(fb)) == -1) {
785                         perror("kmemcpy");
786                         return;
787                 }
788                 fp = &fb;
789                 if (opts & (OPT_HITS|OPT_VERBOSE))
790 #ifdef  USE_QUAD_T
791                         PRINTF("%qu ", (unsigned long long) fp->fr_hits);
792 #else
793                         PRINTF("%lu ", fp->fr_hits);
794 #endif
795                 if (opts & (OPT_ACCNT|OPT_VERBOSE))
796 #ifdef  USE_QUAD_T
797                         PRINTF("%qu ", (unsigned long long) fp->fr_bytes);
798 #else
799                         PRINTF("%lu ", fp->fr_bytes);
800 #endif
801                 if (opts & OPT_SHOWLINENO)
802                         PRINTF("@%d ", n);
803                 data = NULL;
804                 type = fp->fr_type & ~FR_T_BUILTIN;
805                 if (type == FR_T_IPF || type == FR_T_BPFOPC) {
806                         if (fp->fr_dsize) {
807                                 data = malloc(fp->fr_dsize);
808
809                                 if (kmemcpy(data, (u_long)fp->fr_data,
810                                             fp->fr_dsize) == -1) {
811                                         perror("kmemcpy");
812                                         return;
813                                 }
814                                 fp->fr_data = data;
815                         }
816                 }
817
818                 printfr(fp, ioctl);
819                 if (opts & OPT_DEBUG) {
820                         binprint(fp, sizeof(*fp));
821                         if (fp->fr_data != NULL && fp->fr_dsize > 0)
822                                 binprint(fp->fr_data, fp->fr_dsize);
823                 }
824                 if (data != NULL)
825                         free(data);
826                 if (fp->fr_grp != NULL) {
827                         if (!kmemcpy((char *)&fg, (u_long)fp->fr_grp,
828                                      sizeof(fg)))
829                                 printlist(fg, comment);
830                 }
831                 if (type == FR_T_CALLFUNC) {
832                         printlist(fp->fr_data, "# callfunc: ");
833                 }
834                 fp = fp->fr_next;
835         }
836 }
837
838 /*
839  * print out all of the asked for rule sets, using the stats struct as
840  * the base from which to get the pointers.
841  */
842 static  void    showlist(fiop)
843 struct  friostat        *fiop;
844 {
845         struct  frentry *fp = NULL;
846         int     i, set;
847
848         set = fiop->f_active;
849         if (opts & OPT_INACTIVE)
850                 set = 1 - set;
851         if (opts & OPT_ACCNT) {
852 #ifdef USE_INET6
853                 if ((use_inet6) && (opts & OPT_OUTQUE)) {
854                         i = F_ACOUT;
855                         fp = (struct frentry *)fiop->f_acctout6[set];
856                 } else if ((use_inet6) && (opts & OPT_INQUE)) {
857                         i = F_ACIN;
858                         fp = (struct frentry *)fiop->f_acctin6[set];
859                 } else
860 #endif
861                 if (opts & OPT_OUTQUE) {
862                         i = F_ACOUT;
863                         fp = (struct frentry *)fiop->f_acctout[set];
864                 } else if (opts & OPT_INQUE) {
865                         i = F_ACIN;
866                         fp = (struct frentry *)fiop->f_acctin[set];
867                 } else {
868                         FPRINTF(stderr, "No -i or -o given with -a\n");
869                         return;
870                 }
871         } else {
872 #ifdef  USE_INET6
873                 if ((use_inet6) && (opts & OPT_OUTQUE)) {
874                         i = F_OUT;
875                         fp = (struct frentry *)fiop->f_fout6[set];
876                 } else if ((use_inet6) && (opts & OPT_INQUE)) {
877                         i = F_IN;
878                         fp = (struct frentry *)fiop->f_fin6[set];
879                 } else
880 #endif
881                 if (opts & OPT_OUTQUE) {
882                         i = F_OUT;
883                         fp = (struct frentry *)fiop->f_fout[set];
884                 } else if (opts & OPT_INQUE) {
885                         i = F_IN;
886                         fp = (struct frentry *)fiop->f_fin[set];
887                 } else
888                         return;
889         }
890         if (opts & OPT_VERBOSE)
891                 FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
892
893         if (opts & OPT_VERBOSE)
894                 PRINTF("fp %p set %d\n", fp, set);
895         if (!fp) {
896                 FPRINTF(stderr, "empty list for %s%s\n",
897                         (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]);
898                 return;
899         }
900         printlist(fp, NULL);
901 }
902
903
904 /*
905  * Display ipfilter stateful filtering information
906  */
907 static void showipstates(ipsp)
908 ips_stat_t *ipsp;
909 {
910         u_long minlen, maxlen, totallen, *buckets;
911         int i, sz;
912
913         sz = sizeof(*buckets) * ipsp->iss_statesize;
914         buckets = (u_long *)malloc(sz);
915         if (kmemcpy((char *)buckets, (u_long)ipsp->iss_bucketlen, sz)) {
916                 free(buckets);
917                 return;
918         }
919
920         /*
921          * If a list of states hasn't been asked for, only print out stats
922          */
923         if (!(opts & OPT_SHOWLIST)) {
924                 PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n",
925                         ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp);
926                 PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits,
927                         ipsp->iss_miss);
928                 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu max bucket\n",
929                         ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_bucketfull);
930                 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu bkts in use\n",
931                         ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse);
932                 PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n",
933                         ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin);
934
935                 PRINTF("State logging %sabled\n",
936                         state_logging ? "en" : "dis");
937
938                 PRINTF("\nState table bucket statistics:\n");
939                 PRINTF("\t%lu in use\t\n", ipsp->iss_inuse);
940
941                 minlen = ipsp->iss_max;
942                 totallen = 0;
943                 maxlen = 0;
944
945                 for (i = 0; i < ipsp->iss_statesize; i++) {
946                         if (buckets[i] > maxlen)
947                                 maxlen = buckets[i];
948                         if (buckets[i] < minlen)
949                                         minlen = buckets[i];
950                         totallen += buckets[i];
951                 }
952
953                 PRINTF("\t%2.2f%% bucket usage\n\t%lu minimal length\n",
954                         ((float)ipsp->iss_inuse / ipsp->iss_statesize) * 100.0,
955                         minlen);
956                 PRINTF("\t%lu maximal length\n\t%.3f average length\n",
957                         maxlen,
958                         ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse :
959                                           0.0);
960
961 #define ENTRIES_PER_LINE 5
962
963                 if (opts & OPT_VERBOSE) {
964                         PRINTF("\nCurrent bucket sizes :\n");
965                         for (i = 0; i < ipsp->iss_statesize; i++) {
966                                 if ((i % ENTRIES_PER_LINE) == 0)
967                                         PRINTF("\t");
968                                 PRINTF("%4d -> %4lu", i, buckets[i]);
969                                 if ((i % ENTRIES_PER_LINE) ==
970                                     (ENTRIES_PER_LINE - 1))
971                                         PRINTF("\n");
972                                 else
973                                         PRINTF("  ");
974                         }
975                         PRINTF("\n");
976                 }
977                 PRINTF("\n");
978
979                 free(buckets);
980                 return;
981         }
982
983         /*
984          * Print out all the state information currently held in the kernel.
985          */
986         while (ipsp->iss_list != NULL) {
987                 ipsp->iss_list = printstate(ipsp->iss_list, opts,
988                                             ipsp->iss_ticks);
989         }
990
991         free(buckets);
992 }
993
994
995 #ifdef STATETOP
996 static int handle_resize = 0, handle_break = 0;
997
998 static void topipstates(saddr, daddr, sport, dport, protocol, ver,
999                         refreshtime, topclosed)
1000 i6addr_t saddr;
1001 i6addr_t daddr;
1002 int sport;
1003 int dport;
1004 int protocol;
1005 int ver;
1006 int refreshtime;
1007 int topclosed;
1008 {
1009         char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
1010         int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
1011         int i, j, winy, tsentry, maxx, maxy, redraw = 0;
1012         int len, srclen, dstlen, forward = 1, c = 0;
1013         ips_stat_t ipsst, *ipsstp = &ipsst;
1014         statetop_t *tstable = NULL, *tp;
1015         ipstate_t ips;
1016         ipfobj_t ipfo;
1017         struct timeval selecttimeout;
1018         char hostnm[HOSTNMLEN];
1019         struct protoent *proto;
1020         fd_set readfd;
1021         time_t t;
1022
1023         /* install signal handlers */
1024         signal(SIGINT, sig_break);
1025         signal(SIGQUIT, sig_break);
1026         signal(SIGTERM, sig_break);
1027         signal(SIGWINCH, sig_resize);
1028
1029         /* init ncurses stuff */
1030         initscr();
1031         cbreak();
1032         noecho();
1033         curs_set(0);
1034         timeout(0);
1035         getmaxyx(stdscr, maxy, maxx);
1036
1037         /* init hostname */
1038         gethostname(hostnm, sizeof(hostnm) - 1);
1039         hostnm[sizeof(hostnm) - 1] = '\0';
1040
1041         /* init ipfobj_t stuff */
1042         bzero((caddr_t)&ipfo, sizeof(ipfo));
1043         ipfo.ipfo_rev = IPFILTER_VERSION;
1044         ipfo.ipfo_size = sizeof(*ipsstp);
1045         ipfo.ipfo_ptr = (void *)ipsstp;
1046         ipfo.ipfo_type = IPFOBJ_STATESTAT;
1047
1048         /* repeat until user aborts */
1049         while ( 1 ) {
1050
1051                 /* get state table */
1052                 bzero((char *)&ipsst, sizeof(ipsst));
1053                 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
1054                         perror("ioctl(SIOCGETFS)");
1055                         exit(-1);
1056                 }
1057
1058                 /* clear the history */
1059                 tsentry = -1;
1060
1061                 /* reset max str len */
1062                 srclen = dstlen = 0;
1063
1064                 /* read the state table and store in tstable */
1065                 for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
1066
1067                         if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list,
1068                                     sizeof(ips)))
1069                                 break;
1070
1071                         if (ips.is_v != ver)
1072                                 continue;
1073
1074                         /* check v4 src/dest addresses */
1075                         if (ips.is_v == 4) {
1076                                 if ((saddr.in4.s_addr != INADDR_ANY &&
1077                                      saddr.in4.s_addr != ips.is_saddr) ||
1078                                     (daddr.in4.s_addr != INADDR_ANY &&
1079                                      daddr.in4.s_addr != ips.is_daddr))
1080                                         continue;
1081                         }
1082 #ifdef  USE_INET6
1083                         /* check v6 src/dest addresses */
1084                         if (ips.is_v == 6) {
1085                                 if ((IP6_NEQ(&saddr, &in6addr_any) &&
1086                                      IP6_NEQ(&saddr, &ips.is_src)) ||
1087                                     (IP6_NEQ(&daddr, &in6addr_any) &&
1088                                      IP6_NEQ(&daddr, &ips.is_dst)))
1089                                         continue;
1090                         }
1091 #endif
1092                         /* check protocol */
1093                         if (protocol > 0 && protocol != ips.is_p)
1094                                 continue;
1095
1096                         /* check ports if protocol is TCP or UDP */
1097                         if (((ips.is_p == IPPROTO_TCP) ||
1098                              (ips.is_p == IPPROTO_UDP)) &&
1099                            (((sport > 0) && (htons(sport) != ips.is_sport)) ||
1100                             ((dport > 0) && (htons(dport) != ips.is_dport))))
1101                                 continue;
1102
1103                         /* show closed TCP sessions ? */
1104                         if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
1105                             (ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
1106                             (ips.is_state[1] >= IPF_TCPS_LAST_ACK))
1107                                 continue;
1108
1109                         /*
1110                          * if necessary make room for this state
1111                          * entry
1112                          */
1113                         tsentry++;
1114                         if (!maxtsentries || tsentry == maxtsentries) {
1115                                 maxtsentries += STGROWSIZE;
1116                                 tstable = realloc(tstable,
1117                                     maxtsentries * sizeof(statetop_t));
1118                                 if (tstable == NULL) {
1119                                         perror("realloc");
1120                                         exit(-1);
1121                                 }
1122                         }
1123
1124                         /* get max src/dest address string length */
1125                         len = strlen(getip(ips.is_v, &ips.is_src));
1126                         if (srclen < len)
1127                                 srclen = len;
1128                         len = strlen(getip(ips.is_v, &ips.is_dst));
1129                         if (dstlen < len)
1130                                 dstlen = len;
1131
1132                         /* fill structure */
1133                         tp = tstable + tsentry;
1134                         tp->st_src = ips.is_src;
1135                         tp->st_dst = ips.is_dst;
1136                         tp->st_p = ips.is_p;
1137                         tp->st_v = ips.is_v;
1138                         tp->st_state[0] = ips.is_state[0];
1139                         tp->st_state[1] = ips.is_state[1];
1140                         if (forward) {
1141                                 tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
1142                                 tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
1143                         } else {
1144                                 tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3];
1145                                 tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3];
1146                         }
1147                         tp->st_age = ips.is_die - ipsstp->iss_ticks;
1148                         if ((ips.is_p == IPPROTO_TCP) ||
1149                             (ips.is_p == IPPROTO_UDP)) {
1150                                 tp->st_sport = ips.is_sport;
1151                                 tp->st_dport = ips.is_dport;
1152                         }
1153                 }
1154
1155
1156                 /* sort the array */
1157                 if (tsentry != -1) {
1158                         switch (sorting)
1159                         {
1160                         case STSORT_PR:
1161                                 qsort(tstable, tsentry + 1,
1162                                       sizeof(statetop_t), sort_p);
1163                                 break;
1164                         case STSORT_PKTS:
1165                                 qsort(tstable, tsentry + 1,
1166                                       sizeof(statetop_t), sort_pkts);
1167                                 break;
1168                         case STSORT_BYTES:
1169                                 qsort(tstable, tsentry + 1,
1170                                       sizeof(statetop_t), sort_bytes);
1171                                 break;
1172                         case STSORT_TTL:
1173                                 qsort(tstable, tsentry + 1,
1174                                       sizeof(statetop_t), sort_ttl);
1175                                 break;
1176                         case STSORT_SRCIP:
1177                                 qsort(tstable, tsentry + 1,
1178                                       sizeof(statetop_t), sort_srcip);
1179                                 break;
1180                         case STSORT_SRCPT:
1181                                 qsort(tstable, tsentry +1,
1182                                         sizeof(statetop_t), sort_srcpt);
1183                                 break;
1184                         case STSORT_DSTIP:
1185                                 qsort(tstable, tsentry + 1,
1186                                       sizeof(statetop_t), sort_dstip);
1187                                 break;
1188                         case STSORT_DSTPT:
1189                                 qsort(tstable, tsentry + 1,
1190                                       sizeof(statetop_t), sort_dstpt);
1191                                 break;
1192                         default:
1193                                 break;
1194                         }
1195                 }
1196
1197                 /* handle window resizes */
1198                 if (handle_resize) {
1199                         endwin();
1200                         initscr();
1201                         cbreak();
1202                         noecho();
1203                         curs_set(0);
1204                         timeout(0);
1205                         getmaxyx(stdscr, maxy, maxx);
1206                         redraw = 1;
1207                         handle_resize = 0;
1208                 }
1209
1210                 /* stop program? */
1211                 if (handle_break)
1212                         break;
1213
1214                 /* print title */
1215                 erase();
1216                 attron(A_BOLD);
1217                 winy = 0;
1218                 move(winy,0);
1219                 sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION);
1220                 for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
1221                         printw(" ");
1222                 printw("%s", str1);
1223                 attroff(A_BOLD);
1224
1225                 /* just for fun add a clock */
1226                 move(winy, maxx - 8);
1227                 t = time(NULL);
1228                 strftime(str1, 80, "%T", localtime(&t));
1229                 printw("%s\n", str1);
1230
1231                 /*
1232                  * print the display filters, this is placed in the loop,
1233                  * because someday I might add code for changing these
1234                  * while the programming is running :-)
1235                  */
1236                 if (sport >= 0)
1237                         sprintf(str1, "%s,%d", getip(ver, &saddr), sport);
1238                 else
1239                         sprintf(str1, "%s", getip(ver, &saddr));
1240
1241                 if (dport >= 0)
1242                         sprintf(str2, "%s,%d", getip(ver, &daddr), dport);
1243                 else
1244                         sprintf(str2, "%s", getip(ver, &daddr));
1245
1246                 if (protocol < 0)
1247                         strcpy(str3, "any");
1248                 else if ((proto = getprotobynumber(protocol)) != NULL)
1249                         sprintf(str3, "%s", proto->p_name);
1250                 else
1251                         sprintf(str3, "%d", protocol);
1252
1253                 switch (sorting)
1254                 {
1255                 case STSORT_PR:
1256                         sprintf(str4, "proto");
1257                         break;
1258                 case STSORT_PKTS:
1259                         sprintf(str4, "# pkts");
1260                         break;
1261                 case STSORT_BYTES:
1262                         sprintf(str4, "# bytes");
1263                         break;
1264                 case STSORT_TTL:
1265                         sprintf(str4, "ttl");
1266                         break;
1267                 case STSORT_SRCIP:
1268                         sprintf(str4, "src ip");
1269                         break;
1270                 case STSORT_SRCPT:
1271                         sprintf(str4, "src port");
1272                         break;
1273                 case STSORT_DSTIP:
1274                         sprintf(str4, "dest ip");
1275                         break;
1276                 case STSORT_DSTPT:
1277                         sprintf(str4, "dest port");
1278                         break;
1279                 default:
1280                         sprintf(str4, "unknown");
1281                         break;
1282                 }
1283
1284                 if (reverse)
1285                         strcat(str4, " (reverse)");
1286
1287                 winy += 2;
1288                 move(winy,0);
1289                 printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
1290                        str1, str2, str3, str4);
1291
1292                 /* 
1293                  * For an IPv4 IP address we need at most 15 characters,
1294                  * 4 tuples of 3 digits, separated by 3 dots. Enforce this
1295                  * length, so the colums do not change positions based
1296                  * on the size of the IP address. This length makes the
1297                  * output fit in a 80 column terminal. 
1298                  * We are lacking a good solution for IPv6 addresses (that
1299                  * can be longer that 15 characters), so we do not enforce 
1300                  * a maximum on the IP field size.
1301                  */
1302                 if (srclen < 15)
1303                         srclen = 15;
1304                 if (dstlen < 15)
1305                         dstlen = 15;
1306
1307                 /* print column description */
1308                 winy += 2;
1309                 move(winy,0);
1310                 attron(A_BOLD);
1311                 printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
1312                        srclen + 6, "Source IP", dstlen + 6, "Destination IP",
1313                        "ST", "PR", "#pkts", "#bytes", "ttl");
1314                 attroff(A_BOLD);
1315
1316                 /* print all the entries */
1317                 tp = tstable;
1318                 if (reverse)
1319                         tp += tsentry;
1320
1321                 if (tsentry > maxy - 6)
1322                         tsentry = maxy - 6;
1323                 for (i = 0; i <= tsentry; i++) {
1324                         /* print src/dest and port */
1325                         if ((tp->st_p == IPPROTO_TCP) ||
1326                             (tp->st_p == IPPROTO_UDP)) {
1327                                 sprintf(str1, "%s,%hu",
1328                                         getip(tp->st_v, &tp->st_src),
1329                                         ntohs(tp->st_sport));
1330                                 sprintf(str2, "%s,%hu",
1331                                         getip(tp->st_v, &tp->st_dst),
1332                                         ntohs(tp->st_dport));
1333                         } else {
1334                                 sprintf(str1, "%s", getip(tp->st_v,
1335                                     &tp->st_src));
1336                                 sprintf(str2, "%s", getip(tp->st_v,
1337                                     &tp->st_dst));
1338                         }
1339                         winy++;
1340                         move(winy, 0);
1341                         printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
1342
1343                         /* print state */
1344                         sprintf(str1, "%X/%X", tp->st_state[0],
1345                                 tp->st_state[1]);
1346                         printw(" %3s", str1);
1347
1348                         /* print protocol */
1349                         proto = getprotobynumber(tp->st_p);
1350                         if (proto) {
1351                                 strncpy(str1, proto->p_name, 4);
1352                                 str1[4] = '\0';
1353                         } else {
1354                                 sprintf(str1, "%d", tp->st_p);
1355                         }
1356                         /* just print icmp for IPv6-ICMP */
1357                         if (tp->st_p == IPPROTO_ICMPV6)
1358                                 strcpy(str1, "icmp");
1359                         printw(" %4s", str1);
1360
1361                         /* print #pkt/#bytes */
1362 #ifdef  USE_QUAD_T
1363                         printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
1364                                 (unsigned long long) tp->st_bytes);
1365 #else
1366                         printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
1367 #endif
1368                         printw(" %9s", ttl_to_string(tp->st_age));
1369
1370                         if (reverse)
1371                                 tp--;
1372                         else
1373                                 tp++;
1374                 }
1375
1376                 /* screen data structure is filled, now update the screen */
1377                 if (redraw)
1378                         clearok(stdscr,1);
1379
1380                 if (refresh() == ERR)
1381                         break;
1382                 if (redraw) {
1383                         clearok(stdscr,0);
1384                         redraw = 0;
1385                 }
1386
1387                 /* wait for key press or a 1 second time out period */
1388                 selecttimeout.tv_sec = refreshtime;
1389                 selecttimeout.tv_usec = 0;
1390                 FD_ZERO(&readfd);
1391                 FD_SET(0, &readfd);
1392                 select(1, &readfd, NULL, NULL, &selecttimeout);
1393
1394                 /* if key pressed, read all waiting keys */
1395                 if (FD_ISSET(0, &readfd)) {
1396                         c = wgetch(stdscr);
1397                         if (c == ERR)
1398                                 continue;
1399
1400                         if (ISALPHA(c) && ISUPPER(c))
1401                                 c = TOLOWER(c);
1402                         if (c == 'l') {
1403                                 redraw = 1;
1404                         } else if (c == 'q') {
1405                                 break;
1406                         } else if (c == 'r') {
1407                                 reverse = !reverse;
1408                         } else if (c == 'b') {
1409                                 forward = 0;
1410                         } else if (c == 'f') {
1411                                 forward = 1;
1412                         } else if (c == 's') {
1413                                 if (++sorting > STSORT_MAX)
1414                                         sorting = 0;
1415                         }
1416                 }
1417         } /* while */
1418
1419         printw("\n");
1420         curs_set(1);
1421         nocbreak();
1422         endwin();
1423
1424         free(tstable);
1425 }
1426 #endif
1427
1428
1429 /*
1430  * Show fragment cache information that's held in the kernel.
1431  */
1432 static void showfrstates(ifsp)
1433 ipfrstat_t *ifsp;
1434 {
1435         struct ipfr *ipfrtab[IPFT_SIZE], ifr;
1436         int i;
1437
1438         /*
1439          * print out the numeric statistics
1440          */
1441         PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n",
1442                 ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
1443         PRINTF("\t%lu retrans\n\t%lu too short\n",
1444                 ifsp->ifs_retrans0, ifsp->ifs_short);
1445         PRINTF("\t%lu no memory\n\t%lu already exist\n",
1446                 ifsp->ifs_nomem, ifsp->ifs_exists);
1447         PRINTF("\t%lu inuse\n", ifsp->ifs_inuse);
1448         if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab)))
1449                 return;
1450
1451         /*
1452          * Print out the contents (if any) of the fragment cache table.
1453          */
1454         PRINTF("\n");
1455         for (i = 0; i < IPFT_SIZE; i++)
1456                 while (ipfrtab[i] != NULL) {
1457                         if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1458                                     sizeof(ifr)) == -1)
1459                                 break;
1460                         printfraginfo("", &ifr);
1461                         ipfrtab[i] = ifr.ipfr_next;
1462                 }
1463         /*
1464          * Print out the contents (if any) of the NAT fragment cache table.
1465          */
1466         if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,sizeof(ipfrtab)))
1467                 return;
1468         for (i = 0; i < IPFT_SIZE; i++)
1469                 while (ipfrtab[i] != NULL) {
1470                         if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1471                                     sizeof(ifr)) == -1)
1472                                 break;
1473                         printfraginfo("NAT: ", &ifr);
1474                         ipfrtab[i] = ifr.ipfr_next;
1475                 }
1476 }
1477
1478
1479 /*
1480  * Show stats on how auth within IPFilter has been used
1481  */
1482 static void showauthstates(asp)
1483 fr_authstat_t *asp;
1484 {
1485         frauthent_t *frap, fra;
1486
1487 #ifdef  USE_QUAD_T
1488         printf("Authorisation hits: %qu\tmisses %qu\n",
1489                 (unsigned long long) asp->fas_hits,
1490                 (unsigned long long) asp->fas_miss);
1491 #else
1492         printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
1493                 asp->fas_miss);
1494 #endif
1495         printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
1496                 asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
1497                 asp->fas_sendok);
1498         printf("queok %ld\nquefail %ld\nexpire %ld\n",
1499                 asp->fas_queok, asp->fas_quefail, asp->fas_expire);
1500
1501         frap = asp->fas_faelist;
1502         while (frap) {
1503                 if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1)
1504                         break;
1505
1506                 printf("age %ld\t", fra.fae_age);
1507                 printfr(&fra.fae_fr, ioctl);
1508                 frap = fra.fae_next;
1509         }
1510 }
1511
1512
1513 /*
1514  * Display groups used for each of filter rules, accounting rules and
1515  * authentication, separately.
1516  */
1517 static void showgroups(fiop)
1518 struct friostat *fiop;
1519 {
1520         static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
1521         static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH };
1522         frgroup_t *fp, grp;
1523         int on, off, i;
1524
1525         on = fiop->f_active;
1526         off = 1 - on;
1527
1528         for (i = 0; i < 3; i++) {
1529                 printf("%s groups (active):\n", gnames[i]);
1530                 for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL;
1531                      fp = grp.fg_next)
1532                         if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1533                                 break;
1534                         else
1535                                 printf("%s\n", grp.fg_name);
1536                 printf("%s groups (inactive):\n", gnames[i]);
1537                 for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL;
1538                      fp = grp.fg_next)
1539                         if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1540                                 break;
1541                         else
1542                                 printf("%s\n", grp.fg_name);
1543         }
1544 }
1545
1546 static void parse_ipportstr(argument, ip, port)
1547 const char *argument;
1548 i6addr_t *ip;
1549 int *port;
1550 {
1551         char *s, *comma;
1552         int ok = 0;
1553
1554         /* make working copy of argument, Theoretically you must be able
1555          * to write to optarg, but that seems very ugly to me....
1556          */
1557         s = strdup(argument);
1558         if (s == NULL)
1559                 return;
1560
1561         /* get port */
1562         if ((comma = strchr(s, ',')) != NULL) {
1563                 if (!strcasecmp(comma + 1, "any")) {
1564                         *port = -1;
1565                 } else if (!sscanf(comma + 1, "%d", port) ||
1566                            (*port < 0) || (*port > 65535)) {
1567                         fprintf(stderr, "Invalid port specfication in %s\n",
1568                                 argument);
1569                         free(s);
1570                         exit(-2);
1571                 }
1572                 *comma = '\0';
1573         }
1574
1575
1576         /* get ip address */
1577         if (!strcasecmp(s, "any")) {
1578                 ip->in4.s_addr = INADDR_ANY;
1579 #ifdef  USE_INET6
1580                 ip->in6 = in6addr_any;
1581         } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) {
1582                 ok = 1;
1583 #endif
1584         } else if (inet_aton(s, &ip->in4))
1585                 ok = 1;
1586
1587         if (ok == 0) {
1588                 fprintf(stderr, "Invalid IP address: %s\n", s);
1589                 free(s);
1590                 exit(-2);
1591         }
1592
1593         /* free allocated memory */
1594         free(s);
1595 }
1596
1597
1598 #ifdef STATETOP
1599 static void sig_resize(s)
1600 int s;
1601 {
1602         handle_resize = 1;
1603 }
1604
1605 static void sig_break(s)
1606 int s;
1607 {
1608         handle_break = 1;
1609 }
1610
1611 static char *getip(v, addr)
1612 int v;
1613 i6addr_t *addr;
1614 {
1615         static char hostbuf[MAXHOSTNAMELEN+1];
1616
1617         if (v == 4)
1618                 return inet_ntoa(addr->in4);
1619
1620 #ifdef  USE_INET6
1621         (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1);
1622         hostbuf[MAXHOSTNAMELEN] = '\0';
1623         return hostbuf;
1624 #else
1625         return "IPv6";
1626 #endif
1627 }
1628
1629
1630 static char *ttl_to_string(ttl)
1631 long int ttl;
1632 {
1633         static char ttlbuf[STSTRSIZE];
1634         int hours, minutes, seconds;
1635
1636         /* ttl is in half seconds */
1637         ttl /= 2;
1638
1639         hours = ttl / 3600;
1640         ttl = ttl % 3600;
1641         minutes = ttl / 60;
1642         seconds = ttl % 60;
1643
1644         if (hours > 0)
1645                 sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds);
1646         else
1647                 sprintf(ttlbuf, "%2d:%02d", minutes, seconds);
1648         return ttlbuf;
1649 }
1650
1651
1652 static int sort_pkts(a, b)
1653 const void *a;
1654 const void *b;
1655 {
1656
1657         register const statetop_t *ap = a;
1658         register const statetop_t *bp = b;
1659
1660         if (ap->st_pkts == bp->st_pkts)
1661                 return 0;
1662         else if (ap->st_pkts < bp->st_pkts)
1663                 return 1;
1664         return -1;
1665 }
1666
1667
1668 static int sort_bytes(a, b)
1669 const void *a;
1670 const void *b;
1671 {
1672         register const statetop_t *ap = a;
1673         register const statetop_t *bp = b;
1674
1675         if (ap->st_bytes == bp->st_bytes)
1676                 return 0;
1677         else if (ap->st_bytes < bp->st_bytes)
1678                 return 1;
1679         return -1;
1680 }
1681
1682
1683 static int sort_p(a, b)
1684 const void *a;
1685 const void *b;
1686 {
1687         register const statetop_t *ap = a;
1688         register const statetop_t *bp = b;
1689
1690         if (ap->st_p == bp->st_p)
1691                 return 0;
1692         else if (ap->st_p < bp->st_p)
1693                 return 1;
1694         return -1;
1695 }
1696
1697
1698 static int sort_ttl(a, b)
1699 const void *a;
1700 const void *b;
1701 {
1702         register const statetop_t *ap = a;
1703         register const statetop_t *bp = b;
1704
1705         if (ap->st_age == bp->st_age)
1706                 return 0;
1707         else if (ap->st_age < bp->st_age)
1708                 return 1;
1709         return -1;
1710 }
1711
1712 static int sort_srcip(a, b)
1713 const void *a;
1714 const void *b;
1715 {
1716         register const statetop_t *ap = a;
1717         register const statetop_t *bp = b;
1718
1719 #ifdef USE_INET6
1720         if (use_inet6) {
1721                 if (IP6_EQ(&ap->st_src, &bp->st_src))
1722                         return 0;
1723                 else if (IP6_GT(&ap->st_src, &bp->st_src))
1724                         return 1;
1725         } else
1726 #endif
1727         {
1728                 if (ntohl(ap->st_src.in4.s_addr) ==
1729                     ntohl(bp->st_src.in4.s_addr))
1730                         return 0;
1731                 else if (ntohl(ap->st_src.in4.s_addr) >
1732                          ntohl(bp->st_src.in4.s_addr))
1733                         return 1;
1734         }
1735         return -1;
1736 }
1737
1738 static int sort_srcpt(a, b)
1739 const void *a;
1740 const void *b;
1741 {
1742         register const statetop_t *ap = a;
1743         register const statetop_t *bp = b;
1744
1745         if (htons(ap->st_sport) == htons(bp->st_sport))
1746                 return 0;
1747         else if (htons(ap->st_sport) > htons(bp->st_sport))
1748                 return 1;
1749         return -1;
1750 }
1751
1752 static int sort_dstip(a, b)
1753 const void *a;
1754 const void *b;
1755 {
1756         register const statetop_t *ap = a;
1757         register const statetop_t *bp = b;
1758
1759 #ifdef USE_INET6
1760         if (use_inet6) {
1761                 if (IP6_EQ(&ap->st_dst, &bp->st_dst))
1762                         return 0;
1763                 else if (IP6_GT(&ap->st_dst, &bp->st_dst))
1764                         return 1;
1765         } else
1766 #endif
1767         {
1768                 if (ntohl(ap->st_dst.in4.s_addr) ==
1769                     ntohl(bp->st_dst.in4.s_addr))
1770                         return 0;
1771                 else if (ntohl(ap->st_dst.in4.s_addr) >
1772                          ntohl(bp->st_dst.in4.s_addr))
1773                         return 1;
1774         }
1775         return -1;
1776 }
1777
1778 static int sort_dstpt(a, b)
1779 const void *a;
1780 const void *b;
1781 {
1782         register const statetop_t *ap = a;
1783         register const statetop_t *bp = b;
1784
1785         if (htons(ap->st_dport) == htons(bp->st_dport))
1786                 return 0;
1787         else if (htons(ap->st_dport) > htons(bp->st_dport))
1788                 return 1;
1789         return -1;
1790 }
1791
1792 #endif