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