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