]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/tools/ipfstat.c
This commit was generated by cvs2svn to compensate for changes in r155832,
[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.13 2005/10/17 17:26:32 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, ret = 0;
1012         int len, srclen, dstlen, forward = 1, c = 0;
1013         ips_stat_t ipsst, *ipsstp = &ipsst;
1014         statetop_t *tstable = NULL, *tp;
1015         const char *errstr = "";
1016         ipstate_t ips;
1017         ipfobj_t ipfo;
1018         struct timeval selecttimeout;
1019         char hostnm[HOSTNMLEN];
1020         struct protoent *proto;
1021         fd_set readfd;
1022         time_t t;
1023
1024         /* install signal handlers */
1025         signal(SIGINT, sig_break);
1026         signal(SIGQUIT, sig_break);
1027         signal(SIGTERM, sig_break);
1028         signal(SIGWINCH, sig_resize);
1029
1030         /* init ncurses stuff */
1031         initscr();
1032         cbreak();
1033         noecho();
1034         curs_set(0);
1035         timeout(0);
1036         getmaxyx(stdscr, maxy, maxx);
1037
1038         /* init hostname */
1039         gethostname(hostnm, sizeof(hostnm) - 1);
1040         hostnm[sizeof(hostnm) - 1] = '\0';
1041
1042         /* init ipfobj_t stuff */
1043         bzero((caddr_t)&ipfo, sizeof(ipfo));
1044         ipfo.ipfo_rev = IPFILTER_VERSION;
1045         ipfo.ipfo_size = sizeof(*ipsstp);
1046         ipfo.ipfo_ptr = (void *)ipsstp;
1047         ipfo.ipfo_type = IPFOBJ_STATESTAT;
1048
1049         /* repeat until user aborts */
1050         while ( 1 ) {
1051
1052                 /* get state table */
1053                 bzero((char *)&ipsst, sizeof(ipsst));
1054                 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
1055                         errstr = "ioctl(SIOCGETFS)";
1056                         ret = -1;
1057                         goto out;
1058                 }
1059
1060                 /* clear the history */
1061                 tsentry = -1;
1062
1063                 /* reset max str len */
1064                 srclen = dstlen = 0;
1065
1066                 /* read the state table and store in tstable */
1067                 for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
1068
1069                         if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list,
1070                                     sizeof(ips)))
1071                                 break;
1072
1073                         if (ips.is_v != ver)
1074                                 continue;
1075
1076                         /* check v4 src/dest addresses */
1077                         if (ips.is_v == 4) {
1078                                 if ((saddr.in4.s_addr != INADDR_ANY &&
1079                                      saddr.in4.s_addr != ips.is_saddr) ||
1080                                     (daddr.in4.s_addr != INADDR_ANY &&
1081                                      daddr.in4.s_addr != ips.is_daddr))
1082                                         continue;
1083                         }
1084 #ifdef  USE_INET6
1085                         /* check v6 src/dest addresses */
1086                         if (ips.is_v == 6) {
1087                                 if ((IP6_NEQ(&saddr, &in6addr_any) &&
1088                                      IP6_NEQ(&saddr, &ips.is_src)) ||
1089                                     (IP6_NEQ(&daddr, &in6addr_any) &&
1090                                      IP6_NEQ(&daddr, &ips.is_dst)))
1091                                         continue;
1092                         }
1093 #endif
1094                         /* check protocol */
1095                         if (protocol > 0 && protocol != ips.is_p)
1096                                 continue;
1097
1098                         /* check ports if protocol is TCP or UDP */
1099                         if (((ips.is_p == IPPROTO_TCP) ||
1100                              (ips.is_p == IPPROTO_UDP)) &&
1101                            (((sport > 0) && (htons(sport) != ips.is_sport)) ||
1102                             ((dport > 0) && (htons(dport) != ips.is_dport))))
1103                                 continue;
1104
1105                         /* show closed TCP sessions ? */
1106                         if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
1107                             (ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
1108                             (ips.is_state[1] >= IPF_TCPS_LAST_ACK))
1109                                 continue;
1110
1111                         /*
1112                          * if necessary make room for this state
1113                          * entry
1114                          */
1115                         tsentry++;
1116                         if (!maxtsentries || tsentry == maxtsentries) {
1117                                 maxtsentries += STGROWSIZE;
1118                                 tstable = realloc(tstable,
1119                                     maxtsentries * sizeof(statetop_t));
1120                                 if (tstable == NULL) {
1121                                         perror("realloc");
1122                                         exit(-1);
1123                                 }
1124                         }
1125
1126                         /* get max src/dest address string length */
1127                         len = strlen(getip(ips.is_v, &ips.is_src));
1128                         if (srclen < len)
1129                                 srclen = len;
1130                         len = strlen(getip(ips.is_v, &ips.is_dst));
1131                         if (dstlen < len)
1132                                 dstlen = len;
1133
1134                         /* fill structure */
1135                         tp = tstable + tsentry;
1136                         tp->st_src = ips.is_src;
1137                         tp->st_dst = ips.is_dst;
1138                         tp->st_p = ips.is_p;
1139                         tp->st_v = ips.is_v;
1140                         tp->st_state[0] = ips.is_state[0];
1141                         tp->st_state[1] = ips.is_state[1];
1142                         if (forward) {
1143                                 tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
1144                                 tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
1145                         } else {
1146                                 tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3];
1147                                 tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3];
1148                         }
1149                         tp->st_age = ips.is_die - ipsstp->iss_ticks;
1150                         if ((ips.is_p == IPPROTO_TCP) ||
1151                             (ips.is_p == IPPROTO_UDP)) {
1152                                 tp->st_sport = ips.is_sport;
1153                                 tp->st_dport = ips.is_dport;
1154                         }
1155                 }
1156
1157
1158                 /* sort the array */
1159                 if (tsentry != -1) {
1160                         switch (sorting)
1161                         {
1162                         case STSORT_PR:
1163                                 qsort(tstable, tsentry + 1,
1164                                       sizeof(statetop_t), sort_p);
1165                                 break;
1166                         case STSORT_PKTS:
1167                                 qsort(tstable, tsentry + 1,
1168                                       sizeof(statetop_t), sort_pkts);
1169                                 break;
1170                         case STSORT_BYTES:
1171                                 qsort(tstable, tsentry + 1,
1172                                       sizeof(statetop_t), sort_bytes);
1173                                 break;
1174                         case STSORT_TTL:
1175                                 qsort(tstable, tsentry + 1,
1176                                       sizeof(statetop_t), sort_ttl);
1177                                 break;
1178                         case STSORT_SRCIP:
1179                                 qsort(tstable, tsentry + 1,
1180                                       sizeof(statetop_t), sort_srcip);
1181                                 break;
1182                         case STSORT_SRCPT:
1183                                 qsort(tstable, tsentry +1,
1184                                         sizeof(statetop_t), sort_srcpt);
1185                                 break;
1186                         case STSORT_DSTIP:
1187                                 qsort(tstable, tsentry + 1,
1188                                       sizeof(statetop_t), sort_dstip);
1189                                 break;
1190                         case STSORT_DSTPT:
1191                                 qsort(tstable, tsentry + 1,
1192                                       sizeof(statetop_t), sort_dstpt);
1193                                 break;
1194                         default:
1195                                 break;
1196                         }
1197                 }
1198
1199                 /* handle window resizes */
1200                 if (handle_resize) {
1201                         endwin();
1202                         initscr();
1203                         cbreak();
1204                         noecho();
1205                         curs_set(0);
1206                         timeout(0);
1207                         getmaxyx(stdscr, maxy, maxx);
1208                         redraw = 1;
1209                         handle_resize = 0;
1210                 }
1211
1212                 /* stop program? */
1213                 if (handle_break)
1214                         break;
1215
1216                 /* print title */
1217                 erase();
1218                 attron(A_BOLD);
1219                 winy = 0;
1220                 move(winy,0);
1221                 sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION);
1222                 for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
1223                         printw(" ");
1224                 printw("%s", str1);
1225                 attroff(A_BOLD);
1226
1227                 /* just for fun add a clock */
1228                 move(winy, maxx - 8);
1229                 t = time(NULL);
1230                 strftime(str1, 80, "%T", localtime(&t));
1231                 printw("%s\n", str1);
1232
1233                 /*
1234                  * print the display filters, this is placed in the loop,
1235                  * because someday I might add code for changing these
1236                  * while the programming is running :-)
1237                  */
1238                 if (sport >= 0)
1239                         sprintf(str1, "%s,%d", getip(ver, &saddr), sport);
1240                 else
1241                         sprintf(str1, "%s", getip(ver, &saddr));
1242
1243                 if (dport >= 0)
1244                         sprintf(str2, "%s,%d", getip(ver, &daddr), dport);
1245                 else
1246                         sprintf(str2, "%s", getip(ver, &daddr));
1247
1248                 if (protocol < 0)
1249                         strcpy(str3, "any");
1250                 else if ((proto = getprotobynumber(protocol)) != NULL)
1251                         sprintf(str3, "%s", proto->p_name);
1252                 else
1253                         sprintf(str3, "%d", protocol);
1254
1255                 switch (sorting)
1256                 {
1257                 case STSORT_PR:
1258                         sprintf(str4, "proto");
1259                         break;
1260                 case STSORT_PKTS:
1261                         sprintf(str4, "# pkts");
1262                         break;
1263                 case STSORT_BYTES:
1264                         sprintf(str4, "# bytes");
1265                         break;
1266                 case STSORT_TTL:
1267                         sprintf(str4, "ttl");
1268                         break;
1269                 case STSORT_SRCIP:
1270                         sprintf(str4, "src ip");
1271                         break;
1272                 case STSORT_SRCPT:
1273                         sprintf(str4, "src port");
1274                         break;
1275                 case STSORT_DSTIP:
1276                         sprintf(str4, "dest ip");
1277                         break;
1278                 case STSORT_DSTPT:
1279                         sprintf(str4, "dest port");
1280                         break;
1281                 default:
1282                         sprintf(str4, "unknown");
1283                         break;
1284                 }
1285
1286                 if (reverse)
1287                         strcat(str4, " (reverse)");
1288
1289                 winy += 2;
1290                 move(winy,0);
1291                 printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
1292                        str1, str2, str3, str4);
1293
1294                 /* 
1295                  * For an IPv4 IP address we need at most 15 characters,
1296                  * 4 tuples of 3 digits, separated by 3 dots. Enforce this
1297                  * length, so the colums do not change positions based
1298                  * on the size of the IP address. This length makes the
1299                  * output fit in a 80 column terminal. 
1300                  * We are lacking a good solution for IPv6 addresses (that
1301                  * can be longer that 15 characters), so we do not enforce 
1302                  * a maximum on the IP field size.
1303                  */
1304                 if (srclen < 15)
1305                         srclen = 15;
1306                 if (dstlen < 15)
1307                         dstlen = 15;
1308
1309                 /* print column description */
1310                 winy += 2;
1311                 move(winy,0);
1312                 attron(A_BOLD);
1313                 printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
1314                        srclen + 6, "Source IP", dstlen + 6, "Destination IP",
1315                        "ST", "PR", "#pkts", "#bytes", "ttl");
1316                 attroff(A_BOLD);
1317
1318                 /* print all the entries */
1319                 tp = tstable;
1320                 if (reverse)
1321                         tp += tsentry;
1322
1323                 if (tsentry > maxy - 6)
1324                         tsentry = maxy - 6;
1325                 for (i = 0; i <= tsentry; i++) {
1326                         /* print src/dest and port */
1327                         if ((tp->st_p == IPPROTO_TCP) ||
1328                             (tp->st_p == IPPROTO_UDP)) {
1329                                 sprintf(str1, "%s,%hu",
1330                                         getip(tp->st_v, &tp->st_src),
1331                                         ntohs(tp->st_sport));
1332                                 sprintf(str2, "%s,%hu",
1333                                         getip(tp->st_v, &tp->st_dst),
1334                                         ntohs(tp->st_dport));
1335                         } else {
1336                                 sprintf(str1, "%s", getip(tp->st_v,
1337                                     &tp->st_src));
1338                                 sprintf(str2, "%s", getip(tp->st_v,
1339                                     &tp->st_dst));
1340                         }
1341                         winy++;
1342                         move(winy, 0);
1343                         printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
1344
1345                         /* print state */
1346                         sprintf(str1, "%X/%X", tp->st_state[0],
1347                                 tp->st_state[1]);
1348                         printw(" %3s", str1);
1349
1350                         /* print protocol */
1351                         proto = getprotobynumber(tp->st_p);
1352                         if (proto) {
1353                                 strncpy(str1, proto->p_name, 4);
1354                                 str1[4] = '\0';
1355                         } else {
1356                                 sprintf(str1, "%d", tp->st_p);
1357                         }
1358                         /* just print icmp for IPv6-ICMP */
1359                         if (tp->st_p == IPPROTO_ICMPV6)
1360                                 strcpy(str1, "icmp");
1361                         printw(" %4s", str1);
1362
1363                         /* print #pkt/#bytes */
1364 #ifdef  USE_QUAD_T
1365                         printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
1366                                 (unsigned long long) tp->st_bytes);
1367 #else
1368                         printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
1369 #endif
1370                         printw(" %9s", ttl_to_string(tp->st_age));
1371
1372                         if (reverse)
1373                                 tp--;
1374                         else
1375                                 tp++;
1376                 }
1377
1378                 /* screen data structure is filled, now update the screen */
1379                 if (redraw)
1380                         clearok(stdscr,1);
1381
1382                 if (refresh() == ERR)
1383                         break;
1384                 if (redraw) {
1385                         clearok(stdscr,0);
1386                         redraw = 0;
1387                 }
1388
1389                 /* wait for key press or a 1 second time out period */
1390                 selecttimeout.tv_sec = refreshtime;
1391                 selecttimeout.tv_usec = 0;
1392                 FD_ZERO(&readfd);
1393                 FD_SET(0, &readfd);
1394                 select(1, &readfd, NULL, NULL, &selecttimeout);
1395
1396                 /* if key pressed, read all waiting keys */
1397                 if (FD_ISSET(0, &readfd)) {
1398                         c = wgetch(stdscr);
1399                         if (c == ERR)
1400                                 continue;
1401
1402                         if (ISALPHA(c) && ISUPPER(c))
1403                                 c = TOLOWER(c);
1404                         if (c == 'l') {
1405                                 redraw = 1;
1406                         } else if (c == 'q') {
1407                                 break;
1408                         } else if (c == 'r') {
1409                                 reverse = !reverse;
1410                         } else if (c == 'b') {
1411                                 forward = 0;
1412                         } else if (c == 'f') {
1413                                 forward = 1;
1414                         } else if (c == 's') {
1415                                 if (++sorting > STSORT_MAX)
1416                                         sorting = 0;
1417                         }
1418                 }
1419         } /* while */
1420
1421 out:
1422         printw("\n");
1423         curs_set(1);
1424         /* nocbreak(); XXX - endwin() should make this redundant */
1425         endwin();
1426
1427         free(tstable);
1428         if (ret != 0)
1429                 perror(errstr);
1430 }
1431 #endif
1432
1433
1434 /*
1435  * Show fragment cache information that's held in the kernel.
1436  */
1437 static void showfrstates(ifsp)
1438 ipfrstat_t *ifsp;
1439 {
1440         struct ipfr *ipfrtab[IPFT_SIZE], ifr;
1441         int i;
1442
1443         /*
1444          * print out the numeric statistics
1445          */
1446         PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n",
1447                 ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
1448         PRINTF("\t%lu retrans\n\t%lu too short\n",
1449                 ifsp->ifs_retrans0, ifsp->ifs_short);
1450         PRINTF("\t%lu no memory\n\t%lu already exist\n",
1451                 ifsp->ifs_nomem, ifsp->ifs_exists);
1452         PRINTF("\t%lu inuse\n", ifsp->ifs_inuse);
1453         if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab)))
1454                 return;
1455
1456         /*
1457          * Print out the contents (if any) of the fragment cache table.
1458          */
1459         PRINTF("\n");
1460         for (i = 0; i < IPFT_SIZE; i++)
1461                 while (ipfrtab[i] != NULL) {
1462                         if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1463                                     sizeof(ifr)) == -1)
1464                                 break;
1465                         printfraginfo("", &ifr);
1466                         ipfrtab[i] = ifr.ipfr_next;
1467                 }
1468         /*
1469          * Print out the contents (if any) of the NAT fragment cache table.
1470          */
1471         if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,sizeof(ipfrtab)))
1472                 return;
1473         for (i = 0; i < IPFT_SIZE; i++)
1474                 while (ipfrtab[i] != NULL) {
1475                         if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1476                                     sizeof(ifr)) == -1)
1477                                 break;
1478                         printfraginfo("NAT: ", &ifr);
1479                         ipfrtab[i] = ifr.ipfr_next;
1480                 }
1481 }
1482
1483
1484 /*
1485  * Show stats on how auth within IPFilter has been used
1486  */
1487 static void showauthstates(asp)
1488 fr_authstat_t *asp;
1489 {
1490         frauthent_t *frap, fra;
1491
1492 #ifdef  USE_QUAD_T
1493         printf("Authorisation hits: %qu\tmisses %qu\n",
1494                 (unsigned long long) asp->fas_hits,
1495                 (unsigned long long) asp->fas_miss);
1496 #else
1497         printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
1498                 asp->fas_miss);
1499 #endif
1500         printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
1501                 asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
1502                 asp->fas_sendok);
1503         printf("queok %ld\nquefail %ld\nexpire %ld\n",
1504                 asp->fas_queok, asp->fas_quefail, asp->fas_expire);
1505
1506         frap = asp->fas_faelist;
1507         while (frap) {
1508                 if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1)
1509                         break;
1510
1511                 printf("age %ld\t", fra.fae_age);
1512                 printfr(&fra.fae_fr, ioctl);
1513                 frap = fra.fae_next;
1514         }
1515 }
1516
1517
1518 /*
1519  * Display groups used for each of filter rules, accounting rules and
1520  * authentication, separately.
1521  */
1522 static void showgroups(fiop)
1523 struct friostat *fiop;
1524 {
1525         static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
1526         static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH };
1527         frgroup_t *fp, grp;
1528         int on, off, i;
1529
1530         on = fiop->f_active;
1531         off = 1 - on;
1532
1533         for (i = 0; i < 3; i++) {
1534                 printf("%s groups (active):\n", gnames[i]);
1535                 for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL;
1536                      fp = grp.fg_next)
1537                         if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1538                                 break;
1539                         else
1540                                 printf("%s\n", grp.fg_name);
1541                 printf("%s groups (inactive):\n", gnames[i]);
1542                 for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL;
1543                      fp = grp.fg_next)
1544                         if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1545                                 break;
1546                         else
1547                                 printf("%s\n", grp.fg_name);
1548         }
1549 }
1550
1551 static void parse_ipportstr(argument, ip, port)
1552 const char *argument;
1553 i6addr_t *ip;
1554 int *port;
1555 {
1556         char *s, *comma;
1557         int ok = 0;
1558
1559         /* make working copy of argument, Theoretically you must be able
1560          * to write to optarg, but that seems very ugly to me....
1561          */
1562         s = strdup(argument);
1563         if (s == NULL)
1564                 return;
1565
1566         /* get port */
1567         if ((comma = strchr(s, ',')) != NULL) {
1568                 if (!strcasecmp(comma + 1, "any")) {
1569                         *port = -1;
1570                 } else if (!sscanf(comma + 1, "%d", port) ||
1571                            (*port < 0) || (*port > 65535)) {
1572                         fprintf(stderr, "Invalid port specfication in %s\n",
1573                                 argument);
1574                         free(s);
1575                         exit(-2);
1576                 }
1577                 *comma = '\0';
1578         }
1579
1580
1581         /* get ip address */
1582         if (!strcasecmp(s, "any")) {
1583                 ip->in4.s_addr = INADDR_ANY;
1584 #ifdef  USE_INET6
1585                 ip->in6 = in6addr_any;
1586         } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) {
1587                 ok = 1;
1588 #endif
1589         } else if (inet_aton(s, &ip->in4))
1590                 ok = 1;
1591
1592         if (ok == 0) {
1593                 fprintf(stderr, "Invalid IP address: %s\n", s);
1594                 free(s);
1595                 exit(-2);
1596         }
1597
1598         /* free allocated memory */
1599         free(s);
1600 }
1601
1602
1603 #ifdef STATETOP
1604 static void sig_resize(s)
1605 int s;
1606 {
1607         handle_resize = 1;
1608 }
1609
1610 static void sig_break(s)
1611 int s;
1612 {
1613         handle_break = 1;
1614 }
1615
1616 static char *getip(v, addr)
1617 int v;
1618 i6addr_t *addr;
1619 {
1620 #ifdef  USE_INET6
1621         static char hostbuf[MAXHOSTNAMELEN+1];
1622 #endif
1623
1624         if (v == 4)
1625                 return inet_ntoa(addr->in4);
1626
1627 #ifdef  USE_INET6
1628         (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1);
1629         hostbuf[MAXHOSTNAMELEN] = '\0';
1630         return hostbuf;
1631 #else
1632         return "IPv6";
1633 #endif
1634 }
1635
1636
1637 static char *ttl_to_string(ttl)
1638 long int ttl;
1639 {
1640         static char ttlbuf[STSTRSIZE];
1641         int hours, minutes, seconds;
1642
1643         /* ttl is in half seconds */
1644         ttl /= 2;
1645
1646         hours = ttl / 3600;
1647         ttl = ttl % 3600;
1648         minutes = ttl / 60;
1649         seconds = ttl % 60;
1650
1651         if (hours > 0)
1652                 sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds);
1653         else
1654                 sprintf(ttlbuf, "%2d:%02d", minutes, seconds);
1655         return ttlbuf;
1656 }
1657
1658
1659 static int sort_pkts(a, b)
1660 const void *a;
1661 const void *b;
1662 {
1663
1664         register const statetop_t *ap = a;
1665         register const statetop_t *bp = b;
1666
1667         if (ap->st_pkts == bp->st_pkts)
1668                 return 0;
1669         else if (ap->st_pkts < bp->st_pkts)
1670                 return 1;
1671         return -1;
1672 }
1673
1674
1675 static int sort_bytes(a, b)
1676 const void *a;
1677 const void *b;
1678 {
1679         register const statetop_t *ap = a;
1680         register const statetop_t *bp = b;
1681
1682         if (ap->st_bytes == bp->st_bytes)
1683                 return 0;
1684         else if (ap->st_bytes < bp->st_bytes)
1685                 return 1;
1686         return -1;
1687 }
1688
1689
1690 static int sort_p(a, b)
1691 const void *a;
1692 const void *b;
1693 {
1694         register const statetop_t *ap = a;
1695         register const statetop_t *bp = b;
1696
1697         if (ap->st_p == bp->st_p)
1698                 return 0;
1699         else if (ap->st_p < bp->st_p)
1700                 return 1;
1701         return -1;
1702 }
1703
1704
1705 static int sort_ttl(a, b)
1706 const void *a;
1707 const void *b;
1708 {
1709         register const statetop_t *ap = a;
1710         register const statetop_t *bp = b;
1711
1712         if (ap->st_age == bp->st_age)
1713                 return 0;
1714         else if (ap->st_age < bp->st_age)
1715                 return 1;
1716         return -1;
1717 }
1718
1719 static int sort_srcip(a, b)
1720 const void *a;
1721 const void *b;
1722 {
1723         register const statetop_t *ap = a;
1724         register const statetop_t *bp = b;
1725
1726 #ifdef USE_INET6
1727         if (use_inet6) {
1728                 if (IP6_EQ(&ap->st_src, &bp->st_src))
1729                         return 0;
1730                 else if (IP6_GT(&ap->st_src, &bp->st_src))
1731                         return 1;
1732         } else
1733 #endif
1734         {
1735                 if (ntohl(ap->st_src.in4.s_addr) ==
1736                     ntohl(bp->st_src.in4.s_addr))
1737                         return 0;
1738                 else if (ntohl(ap->st_src.in4.s_addr) >
1739                          ntohl(bp->st_src.in4.s_addr))
1740                         return 1;
1741         }
1742         return -1;
1743 }
1744
1745 static int sort_srcpt(a, b)
1746 const void *a;
1747 const void *b;
1748 {
1749         register const statetop_t *ap = a;
1750         register const statetop_t *bp = b;
1751
1752         if (htons(ap->st_sport) == htons(bp->st_sport))
1753                 return 0;
1754         else if (htons(ap->st_sport) > htons(bp->st_sport))
1755                 return 1;
1756         return -1;
1757 }
1758
1759 static int sort_dstip(a, b)
1760 const void *a;
1761 const void *b;
1762 {
1763         register const statetop_t *ap = a;
1764         register const statetop_t *bp = b;
1765
1766 #ifdef USE_INET6
1767         if (use_inet6) {
1768                 if (IP6_EQ(&ap->st_dst, &bp->st_dst))
1769                         return 0;
1770                 else if (IP6_GT(&ap->st_dst, &bp->st_dst))
1771                         return 1;
1772         } else
1773 #endif
1774         {
1775                 if (ntohl(ap->st_dst.in4.s_addr) ==
1776                     ntohl(bp->st_dst.in4.s_addr))
1777                         return 0;
1778                 else if (ntohl(ap->st_dst.in4.s_addr) >
1779                          ntohl(bp->st_dst.in4.s_addr))
1780                         return 1;
1781         }
1782         return -1;
1783 }
1784
1785 static int sort_dstpt(a, b)
1786 const void *a;
1787 const void *b;
1788 {
1789         register const statetop_t *ap = a;
1790         register const statetop_t *bp = b;
1791
1792         if (htons(ap->st_dport) == htons(bp->st_dport))
1793                 return 0;
1794         else if (htons(ap->st_dport) > htons(bp->st_dport))
1795                 return 1;
1796         return -1;
1797 }
1798
1799 #endif