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