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