Import initial version of 1:1 pthread library.
[dragonfly.git] / contrib / ipfilter / fils.c
1 /*
2  * Copyright (C) 1993-2001 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 #if defined(__sgi) && (IRIX > 602)
16 # include <sys/ptimers.h>
17 #endif
18 #include <stdio.h>
19 #include <string.h>
20 #if !defined(__SVR4) && !defined(__svr4__)
21 # include <strings.h>
22 #endif
23 #include <sys/types.h>
24 #include <sys/time.h>
25 #include <sys/param.h>
26 #include <sys/file.h>
27 #if defined(STATETOP)
28 # if defined(_BSDI_VERSION)
29 #  undef STATETOP)
30 # endif
31 # if defined(__FreeBSD__) && \
32      (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000))
33 #  undef STATETOP
34 # endif
35 # if defined(__NetBSD_Version__)
36 #  if (__NetBSD_Version__ < 105000000)
37 #   undef STATETOP
38 #  else
39 #   include <poll.h>
40 #   define USE_POLL
41 #  endif
42 # endif
43 # if defined(sun)
44 #  if defined(__svr4__) || defined(__SVR4)
45 #   include <sys/select.h>
46 #  else
47 #   undef STATETOP      /* NOT supported on SunOS4 */
48 #  endif
49 # endif
50 #endif
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <fcntl.h>
54 #include <stddef.h>
55 #include <nlist.h>
56 #include <sys/socket.h>
57 #include <sys/ioctl.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
60 #include <netinet/in_systm.h>
61 #include <netinet/ip.h>
62 #include <net/if.h>
63 #if __FreeBSD_version >= 300000
64 # include <net/if_var.h>
65 #endif
66 #include <netdb.h>
67 #include <arpa/nameser.h>
68 #include <resolv.h>
69 #include <netinet/tcp.h>
70 #if defined(STATETOP) && !defined(linux)
71 # include <netinet/ip_var.h>
72 # include <netinet/tcp_fsm.h>
73 #endif
74 #include "netinet/ip_compat.h"
75 #include "netinet/ip_fil.h"
76 #include "ipf.h"
77 #include "netinet/ip_nat.h"
78 #include "netinet/ip_frag.h"
79 #include "netinet/ip_state.h"
80 #include "netinet/ip_proxy.h"
81 #include "netinet/ip_auth.h"
82 #ifdef STATETOP
83 # include "netinet/ipl.h"
84 # include <ctype.h>
85 # if SOLARIS || defined(__NetBSD__) || defined(_BSDI_VERSION) || \
86      defined(__sgi)
87 #  ifdef ERR
88 #   undef ERR
89 #  endif
90 #  include <curses.h>
91 # else /* SOLARIS */
92 #  include <ncurses.h>
93 # endif /* SOLARIS */
94 #endif /* STATETOP */
95 #include "kmem.h"
96 #if defined(__NetBSD__) || (__OpenBSD__)
97 # include <paths.h>
98 #endif
99
100 #if !defined(lint)
101 static const char sccsid[] = "@(#)fils.c        1.21 4/20/96 (C) 1993-2000 Darren Reed";
102 static const char rcsid[] = "@(#)$Id: fils.c,v 2.21.2.45 2004/04/10 11:45:48 darrenr Exp $";
103 #endif
104
105 extern  char    *optarg;
106 extern  int     optind;
107
108 #define PRINTF  (void)printf
109 #define FPRINTF (void)fprintf
110 #define F_IN    0
111 #define F_OUT   1
112 #define F_ACIN  2
113 #define F_ACOUT 3
114 static  char    *filters[4] = { "ipfilter(in)", "ipfilter(out)",
115                                 "ipacct(in)", "ipacct(out)" };
116
117 int     opts = 0;
118 int     use_inet6 = 0;
119 int     live_kernel = 1;
120 int     state_fd = -1;
121 int     auth_fd = -1;
122 int     ipf_fd = -1;
123
124 #ifdef STATETOP
125 #define STSTRSIZE       80
126 #define STGROWSIZE      16
127 #define HOSTNMLEN       40
128
129 #define STSORT_PR       0
130 #define STSORT_PKTS     1
131 #define STSORT_BYTES    2
132 #define STSORT_TTL      3
133 #define STSORT_SRCIP    4
134 #define STSORT_DSTIP    5
135 #define STSORT_MAX      STSORT_DSTIP
136 #define STSORT_DEFAULT  STSORT_BYTES
137
138
139 typedef struct statetop {
140         union i6addr    st_src;
141         union i6addr    st_dst;
142         u_short         st_sport;
143         u_short         st_dport;
144         u_char          st_p;
145         u_char          st_state[2];
146         U_QUAD_T        st_pkts;
147         U_QUAD_T        st_bytes;
148         u_long          st_age;
149 } statetop_t;
150 #endif
151
152 extern  int     main __P((int, char *[]));
153 static  void    showstats __P((friostat_t *, u_32_t));
154 static  void    showfrstates __P((ipfrstat_t *));
155 static  void    showlist __P((friostat_t *));
156 static  void    showipstates __P((ips_stat_t *));
157 static  void    showauthstates __P((fr_authstat_t *));
158 static  void    showgroups __P((friostat_t *));
159 static  void    Usage __P((char *));
160 static  void    printlist __P((frentry_t *));
161 static  void    parse_ipportstr __P((const char *, struct in_addr *, int *));
162 static  int     ipfstate_live __P((char *, friostat_t **, ips_stat_t **,
163                                    ipfrstat_t **, fr_authstat_t **, u_32_t *));
164 static  void    ipfstate_dead __P((char *, friostat_t **, ips_stat_t **,
165                                    ipfrstat_t **, fr_authstat_t **, u_32_t *));
166 #ifdef STATETOP
167 static  void    topipstates __P((struct in_addr, struct in_addr, int, int, int, int, int));
168 static  char    *ttl_to_string __P((long));
169 static  int     sort_p __P((const void *, const void *));
170 static  int     sort_pkts __P((const void *, const void *));
171 static  int     sort_bytes __P((const void *, const void *));
172 static  int     sort_ttl __P((const void *, const void *));
173 static  int     sort_srcip __P((const void *, const void *));
174 static  int     sort_dstip __P((const void *, const void *));
175 #endif
176 #if SOLARIS
177 void showqiflist __P((char *));
178 #endif
179
180
181 static void Usage(name)
182 char *name;
183 {
184 #ifdef  USE_INET6
185         fprintf(stderr, "Usage: %s [-6aAfhIinosv] [-d <device>]\n", name);
186 #else
187         fprintf(stderr, "Usage: %s [-aAfhIinosv] [-d <device>]\n", name);
188 #endif
189         fprintf(stderr, "\t\t[-M corefile] [-N symbol-list]\n");
190         fprintf(stderr, "       %s -t [-S source address] [-D destination address] [-P protocol] [-T refreshtime] [-C] [-d <device>]\n", name);
191         exit(1);
192 }
193
194
195 int main(argc,argv)
196 int argc;
197 char *argv[];
198 {
199         fr_authstat_t   frauthst;
200         fr_authstat_t   *frauthstp = &frauthst;
201         friostat_t fio;
202         friostat_t *fiop = &fio;
203         ips_stat_t ipsst;
204         ips_stat_t *ipsstp = &ipsst;
205         ipfrstat_t ifrst;
206         ipfrstat_t *ifrstp = &ifrst;
207         char    *device = IPL_NAME, *memf = NULL;
208         char    *kern = NULL;
209         int     c, myoptind;
210         struct protoent *proto;
211
212         int protocol = -1;              /* -1 = wild card for any protocol */
213         int refreshtime = 1;            /* default update time */
214         int sport = -1;                 /* -1 = wild card for any source port */
215         int dport = -1;                 /* -1 = wild card for any dest port */
216         int topclosed = 0;              /* do not show closed tcp sessions */
217         struct in_addr saddr, daddr;
218         u_32_t frf;
219
220         saddr.s_addr = INADDR_ANY;      /* default any source addr */ 
221         daddr.s_addr = INADDR_ANY;      /* default any dest addr */
222
223         /*
224          * Parse these two arguments now lest there be any buffer overflows
225          * in the parsing of the rest.
226          */
227         myoptind = optind;
228         while ((c = getopt(argc, argv, "6aACfghIilnoqstvd:D:M:N:P:S:T:")) != -1)
229                 switch (c)
230                 {
231                 case 'M' :
232                         memf = optarg;
233                         live_kernel = 0;
234                         break;
235                 case 'N' :
236                         kern = optarg;
237                         live_kernel = 0;
238                         break;
239                 }
240         optind = myoptind;
241
242         if (live_kernel == 1) {
243                 if ((state_fd = open(IPL_STATE, O_RDONLY)) == -1) {
244                         perror("open");
245                         exit(-1);
246                 }
247                 if ((auth_fd = open(IPL_AUTH, O_RDONLY)) == -1) {
248                         perror("open");
249                         exit(-1);
250                 }
251                 if ((ipf_fd = open(device, O_RDONLY)) == -1) {
252                         perror("open");
253                         exit(-1);
254                 }
255         }
256
257         if (kern != NULL || memf != NULL)
258         {
259                 (void)setuid(getuid());
260                 (void)setgid(getgid());
261         }
262
263         if (openkmem(kern, memf) == -1)
264                 exit(-1);
265
266         (void)setuid(getuid());
267         (void)setgid(getgid());
268
269         while ((c = getopt(argc, argv, "6aACfghIilnoqstvd:D:M:N:P:S:T:")) != -1)
270         {
271                 switch (c)
272                 {
273 #ifdef  USE_INET6
274                 case '6' :
275                         use_inet6 = 1;
276                         break;
277 #endif
278                 case 'a' :
279                         opts |= OPT_ACCNT|OPT_SHOWLIST;
280                         break;
281                 case 'A' :
282                         device = IPAUTH_NAME;
283                         opts |= OPT_AUTHSTATS;
284                         break;
285                 case 'C' :
286                         topclosed = 1;
287                         break;
288                 case 'd' :
289                         device = optarg;
290                         break;
291                 case 'D' :
292                         parse_ipportstr(optarg, &daddr, &dport);
293                         break;
294                 case 'f' :
295                         opts |= OPT_FRSTATES;
296                         break;
297                 case 'g' :
298                         opts |= OPT_GROUPS;
299                         break;
300                 case 'h' :
301                         opts |= OPT_HITS;
302                         break;
303                 case 'i' :
304                         opts |= OPT_INQUE|OPT_SHOWLIST;
305                         break;
306                 case 'I' :
307                         opts |= OPT_INACTIVE;
308                         break;
309                 case 'l' :
310                         opts |= OPT_SHOWLIST;
311                         break;
312                 case 'M' :
313                         break;
314                 case 'N' :
315                         break;
316                 case 'n' :
317                         opts |= OPT_SHOWLINENO;
318                         break;
319                 case 'o' :
320                         opts |= OPT_OUTQUE|OPT_SHOWLIST;
321                         break;
322                 case 'P' :
323                         if ((proto = getprotobyname(optarg)) != NULL) {
324                                 protocol = proto->p_proto;
325                         } else if (!sscanf(optarg, "%ud", &protocol) ||
326                                            (protocol < 0)) {
327                                 fprintf(stderr, "%s : Invalid protocol: %s\n",
328                                         argv[0], optarg);
329                                 exit(-2);
330                         }
331                         break;
332                 case 'q' :
333 #if     SOLARIS
334                         showqiflist(kern);
335                         exit(0);
336                         break;
337 #else
338                         fprintf(stderr, "-q only availble on Solaris\n");
339                         exit(1);
340                         break;
341 #endif
342                 case 's' :
343                         opts |= OPT_IPSTATES;
344                         break;
345                 case 'S' :
346                         parse_ipportstr(optarg, &saddr, &sport);
347                         break;
348                 case 't' :
349 #ifdef STATETOP
350                         opts |= OPT_STATETOP;
351                         break;
352 #else
353                         fprintf(stderr,
354                                 "%s : state top facility not compiled in\n",
355                                 argv[0]);
356                         exit(-2);
357 #endif
358                 case 'T' :
359                         if (!sscanf(optarg, "%d", &refreshtime) ||
360                                     (refreshtime <= 0)) {
361                                 fprintf(stderr,
362                                         "%s : Invalid refreshtime < 1 : %s\n",
363                                         argv[0], optarg);
364                                 exit(-2);
365                         }
366                         break;
367                 case 'v' :
368                         opts |= OPT_VERBOSE;
369                         break;
370                 default :
371                         Usage(argv[0]);
372                         break;
373                 }
374         }
375
376         if (live_kernel == 1) {
377                 bzero((char *)&fio, sizeof(fio));
378                 bzero((char *)&ipsst, sizeof(ipsst));
379                 bzero((char *)&ifrst, sizeof(ifrst));
380
381                 ipfstate_live(device, &fiop, &ipsstp, &ifrstp,
382                               &frauthstp, &frf);
383         } else
384                 ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf);
385
386         if (opts & OPT_IPSTATES) {
387                 showipstates(ipsstp);
388         } else if (opts & OPT_SHOWLIST) {
389                 showlist(fiop);
390                 if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){
391                         opts &= ~OPT_OUTQUE;
392                         showlist(fiop);
393                 }
394         } else {
395                 if (opts & OPT_FRSTATES)
396                         showfrstates(ifrstp);
397 #ifdef STATETOP
398                 else if (opts & OPT_STATETOP)
399                         topipstates(saddr, daddr, sport, dport,
400                                     protocol, refreshtime, topclosed);
401 #endif
402                 else if (opts & OPT_AUTHSTATS)
403                         showauthstates(frauthstp);
404                 else if (opts & OPT_GROUPS)
405                         showgroups(fiop);
406                 else
407                         showstats(fiop, frf);
408         }
409         return 0;
410 }
411
412
413 /*
414  * Fill in the stats structures from the live kernel, using a combination
415  * of ioctl's and copying directly from kernel memory.
416  */
417 int ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
418 char *device;
419 friostat_t **fiopp;
420 ips_stat_t **ipsstpp;
421 ipfrstat_t **ifrstpp;
422 fr_authstat_t **frauthstpp;
423 u_32_t *frfp;
424 {
425
426         if (!(opts & OPT_AUTHSTATS) && ioctl(ipf_fd, SIOCGETFS, fiopp) == -1) {
427                 perror("ioctl(ipf:SIOCGETFS)");
428                 exit(-1);
429         }
430
431         if ((opts & OPT_IPSTATES)) {
432                 if ((ioctl(state_fd, SIOCGETFS, ipsstpp) == -1)) {
433                         perror("ioctl(state:SIOCGETFS)");
434                         exit(-1);
435                 }
436         }
437         if ((opts & OPT_FRSTATES) &&
438             (ioctl(ipf_fd, SIOCGFRST, ifrstpp) == -1)) {
439                 perror("ioctl(SIOCGFRST)");
440                 exit(-1);
441         }
442
443         if (opts & OPT_VERBOSE)
444                 PRINTF("opts %#x name %s\n", opts, device);
445
446         if ((opts & OPT_AUTHSTATS) &&
447             (ioctl(auth_fd, SIOCATHST, frauthstpp) == -1)) {
448                 perror("ioctl(SIOCATHST)");
449                 exit(-1);
450         }
451
452         if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1)
453                 perror("ioctl(SIOCGETFF)");
454
455         return ipf_fd;
456 }
457
458
459 /*
460  * Build up the stats structures from data held in the "core" memory.
461  * This is mainly useful when looking at data in crash dumps and ioctl's
462  * just won't work any more.
463  */
464 void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
465 char *kernel;
466 friostat_t **fiopp;
467 ips_stat_t **ipsstpp;
468 ipfrstat_t **ifrstpp;
469 fr_authstat_t **frauthstpp;
470 u_32_t *frfp;
471 {
472         static fr_authstat_t frauthst, *frauthstp;
473         static ips_stat_t ipsst, *ipsstp;
474         static ipfrstat_t ifrst, *ifrstp;
475         static friostat_t fio, *fiop;
476
477         void *rules[2][2];
478         struct nlist deadlist[42] = {
479                 { "fr_authstats" },             /* 0 */
480                 { "fae_list" },
481                 { "ipauth" },
482                 { "fr_authlist" },
483                 { "fr_authstart" },
484                 { "fr_authend" },               /* 5 */
485                 { "fr_authnext" },
486                 { "fr_auth" },
487                 { "fr_authused" },
488                 { "fr_authsize" },
489                 { "fr_defaultauthage" },        /* 10 */
490                 { "fr_authpkts" },
491                 { "fr_auth_lock" },
492                 { "frstats" },
493                 { "ips_stats" },
494                 { "ips_num" },                  /* 15 */
495                 { "ips_wild" },
496                 { "ips_list" },
497                 { "ips_table" },
498                 { "fr_statemax" },
499                 { "fr_statesize" },             /* 20 */
500                 { "fr_state_doflush" },
501                 { "fr_state_lock" },
502                 { "ipfr_heads" },
503                 { "ipfr_nattab" },
504                 { "ipfr_stats" },               /* 25 */
505                 { "ipfr_inuse" },
506                 { "fr_ipfrttl" },
507                 { "fr_frag_lock" },
508                 { "ipfr_timer_id" },
509                 { "fr_nat_lock" },              /* 30 */
510                 { "ipfilter" },
511                 { "ipfilter6" },
512                 { "ipacct" },
513                 { "ipacct6" },
514                 { "ipl_frouteok" },             /* 35 */
515                 { "fr_running" },
516                 { "ipfgroups" },
517                 { "fr_active" },
518                 { "fr_pass" },
519                 { "fr_flags" },                 /* 40 */
520                 { NULL }
521         };
522
523
524         frauthstp = &frauthst;
525         ipsstp = &ipsst;
526         ifrstp = &ifrst;
527         fiop = &fio;
528
529         *frfp = 0;
530         *fiopp = fiop;
531         *ipsstpp = ipsstp;
532         *ifrstpp = ifrstp;
533         *frauthstpp = frauthstp;
534
535         bzero((char *)fiop, sizeof(*fiop));
536         bzero((char *)ipsstp, sizeof(*ipsstp));
537         bzero((char *)ifrstp, sizeof(*ifrstp));
538         bzero((char *)frauthstp, sizeof(*frauthstp));
539
540         if (nlist(kernel, deadlist) == -1) {
541                 fprintf(stderr, "nlist error\n");
542                 return;
543         }
544
545         /*
546          * This is for SIOCGETFF.
547          */
548         kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp));
549
550         /*
551          * f_locks is a combination of the lock variable from each part of
552          * ipfilter (state, auth, nat, fragments).
553          */
554         kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop));
555         kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value,
556                 sizeof(fiop->f_locks[0]));
557         kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value,
558                 sizeof(fiop->f_locks[1]));
559         kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value,
560                 sizeof(fiop->f_locks[2]));
561         kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value,
562                 sizeof(fiop->f_locks[3]));
563
564         /*
565          * Get pointers to each list of rules (active, inactive, in, out)
566          */
567         kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules));
568         fiop->f_fin[0] = rules[0][0];
569         fiop->f_fin[1] = rules[0][1];
570         fiop->f_fout[0] = rules[1][0];
571         fiop->f_fout[1] = rules[1][1];
572
573         /*
574          * Same for IPv6, except make them null if support for it is not
575          * being compiled in.
576          */
577 #ifdef  USE_INET6
578         kmemcpy((char *)&rules, (u_long)deadlist[32].n_value, sizeof(rules));
579         fiop->f_fin6[0] = rules[0][0];
580         fiop->f_fin6[1] = rules[0][1];
581         fiop->f_fout6[0] = rules[1][0];
582         fiop->f_fout6[1] = rules[1][1];
583 #else
584         fiop->f_fin6[0] = NULL;
585         fiop->f_fin6[1] = NULL;
586         fiop->f_fout6[0] = NULL;
587         fiop->f_fout6[1] = NULL;
588 #endif
589
590         /*
591          * Now get accounting rules pointers.
592          */
593         kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules));
594         fiop->f_acctin[0] = rules[0][0];
595         fiop->f_acctin[1] = rules[0][1];
596         fiop->f_acctout[0] = rules[1][0];
597         fiop->f_acctout[1] = rules[1][1];
598
599 #ifdef  USE_INET6
600         kmemcpy((char *)&rules, (u_long)deadlist[34].n_value, sizeof(rules));
601         fiop->f_acctin6[0] = rules[0][0];
602         fiop->f_acctin6[1] = rules[0][1];
603         fiop->f_acctout6[0] = rules[1][0];
604         fiop->f_acctout6[1] = rules[1][1];
605 #else
606         fiop->f_acctin6[0] = NULL;
607         fiop->f_acctin6[1] = NULL;
608         fiop->f_acctout6[0] = NULL;
609         fiop->f_acctout6[1] = NULL;
610 #endif
611
612         /*
613          * A collection of "global" variables used inside the kernel which
614          * are all collected in friostat_t via ioctl.
615          */
616         kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[35].n_value,
617                 sizeof(fiop->f_froute));
618         kmemcpy((char *)&fiop->f_running, (u_long)deadlist[36].n_value,
619                 sizeof(fiop->f_running));
620         kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[37].n_value,
621                 sizeof(fiop->f_groups));
622         kmemcpy((char *)&fiop->f_active, (u_long)deadlist[38].n_value,
623                 sizeof(fiop->f_active));
624         kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[39].n_value,
625                 sizeof(fiop->f_defpass));
626
627         /*
628          * Build up the state information stats structure.
629          */
630         kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp));
631         kmemcpy((char *)&ipsstp->iss_active, (u_long)deadlist[15].n_value,
632                 sizeof(ipsstp->iss_active));
633         ipsstp->iss_table = (void *)deadlist[18].n_value;
634         ipsstp->iss_list = (void *)deadlist[17].n_value;
635
636         /*
637          * Build up the authentiation information stats structure.
638          */
639         kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value,
640                 sizeof(*frauthstp));
641         frauthstp->fas_faelist = (void *)deadlist[1].n_value;
642
643         /*
644          * Build up the fragment information stats structure.
645          */
646         kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value,
647                 sizeof(*ifrstp));
648         ifrstp->ifs_table = (void *)deadlist[23].n_value;
649         ifrstp->ifs_nattab = (void *)deadlist[24].n_value;
650         kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value,
651                 sizeof(ifrstp->ifs_inuse));
652 }
653
654
655 /*
656  * Display the kernel stats for packets blocked and passed and other
657  * associated running totals which are kept.
658  */
659 static  void    showstats(fp, frf)
660 struct  friostat        *fp;
661 u_32_t frf;
662 {
663
664 #if SOLARIS
665         PRINTF("dropped packets:\tin %lu\tout %lu\n",
666                         fp->f_st[0].fr_drop, fp->f_st[1].fr_drop);
667         PRINTF("non-data packets:\tin %lu\tout %lu\n",
668                         fp->f_st[0].fr_notdata, fp->f_st[1].fr_notdata);
669         PRINTF("no-data packets:\tin %lu\tout %lu\n",
670                         fp->f_st[0].fr_nodata, fp->f_st[1].fr_nodata);
671         PRINTF("non-ip packets:\t\tin %lu\tout %lu\n",
672                         fp->f_st[0].fr_notip, fp->f_st[1].fr_notip);
673         PRINTF("   bad packets:\t\tin %lu\tout %lu\n",
674                         fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
675         PRINTF("copied messages:\tin %lu\tout %lu\n",
676                         fp->f_st[0].fr_copy, fp->f_st[1].fr_copy);
677 #endif
678 #ifdef  USE_INET6
679         PRINTF(" IPv6 packets:\t\tin %lu out %lu\n",
680                         fp->f_st[0].fr_ipv6[0], fp->f_st[0].fr_ipv6[1]);
681 #endif
682         PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
683                         fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
684                         fp->f_st[0].fr_nom);
685         PRINTF(" counted %lu short %lu\n", 
686                         fp->f_st[0].fr_acct, fp->f_st[0].fr_short);
687         PRINTF("output packets:\t\tblocked %lu passed %lu nomatch %lu",
688                         fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
689                         fp->f_st[1].fr_nom);
690         PRINTF(" counted %lu short %lu\n", 
691                         fp->f_st[1].fr_acct, fp->f_st[1].fr_short);
692         PRINTF(" input packets logged:\tblocked %lu passed %lu\n",
693                         fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
694         PRINTF("output packets logged:\tblocked %lu passed %lu\n",
695                         fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
696         PRINTF(" packets logged:\tinput %lu output %lu\n",
697                         fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl);
698         PRINTF(" log failures:\t\tinput %lu output %lu\n",
699                         fp->f_st[0].fr_skip, fp->f_st[1].fr_skip);
700         PRINTF("fragment state(in):\tkept %lu\tlost %lu\tnot fragmented %lu\n",
701                         fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr, fp->f_st[0].fr_cfr);
702         PRINTF("fragment state(out):\tkept %lu\tlost %lu\tnot fragmented %lu\n",
703                         fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr, fp->f_st[1].fr_cfr);
704         PRINTF("packet state(in):\tkept %lu\tlost %lu\n",
705                         fp->f_st[0].fr_ads, fp->f_st[0].fr_bads);
706         PRINTF("packet state(out):\tkept %lu\tlost %lu\n",
707                         fp->f_st[1].fr_ads, fp->f_st[1].fr_bads);
708         PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n",
709                         fp->f_st[0].fr_ret, fp->f_st[1].fr_ret);
710         PRINTF("Invalid source(in):\t%lu\n", fp->f_st[0].fr_badsrc);
711         PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n",
712                         fp->f_st[0].fr_chit, fp->f_st[1].fr_chit);
713         PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n",
714                         fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]);
715         PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n",
716                         fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]);
717         PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n",
718                         fp->f_froute[0], fp->f_froute[1]);
719         PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n",
720                         fp->f_st[0].fr_tcpbad, fp->f_st[1].fr_tcpbad);
721
722         PRINTF("Packet log flags set: (%#x)\n", frf);
723         if (frf & FF_LOGPASS)
724                 PRINTF("\tpackets passed through filter\n");
725         if (frf & FF_LOGBLOCK)
726                 PRINTF("\tpackets blocked by filter\n");
727         if (frf & FF_LOGNOMATCH)
728                 PRINTF("\tpackets not matched by filter\n");
729         if (!frf)
730                 PRINTF("\tnone\n");
731 }
732
733
734 /*
735  * Print out a list of rules from the kernel, starting at the one passed.
736  */
737 static void printlist(fp)
738 frentry_t *fp;
739 {
740         struct  frentry fb;
741         int     n;
742
743         for (n = 1; fp; n++) {
744                 if (kmemcpy((char *)&fb, (u_long)fp, sizeof(fb)) == -1) {
745                         perror("kmemcpy");
746                         return;
747                 }
748                 fp = &fb;
749                 if (opts & OPT_OUTQUE)
750                         fp->fr_flags |= FR_OUTQUE;
751                 if (opts & (OPT_HITS|OPT_VERBOSE))
752 #ifdef  USE_QUAD_T
753                         PRINTF("%qu ", (unsigned long long) fp->fr_hits);
754 #else
755                         PRINTF("%lu ", fp->fr_hits);
756 #endif
757                 if (opts & (OPT_ACCNT|OPT_VERBOSE))
758 #ifdef  USE_QUAD_T
759                         PRINTF("%qu ", (unsigned long long) fp->fr_bytes);
760 #else
761                         PRINTF("%lu ", fp->fr_bytes);
762 #endif
763                 if (opts & OPT_SHOWLINENO)
764                         PRINTF("@%d ", n);
765                 printfr(fp);
766                 if (opts & OPT_VERBOSE)
767                         binprint(fp);
768                 if (fp->fr_grp)
769                         printlist(fp->fr_grp);
770                 fp = fp->fr_next;
771         }
772 }
773
774 /*
775  * print out all of the asked for rule sets, using the stats struct as
776  * the base from which to get the pointers.
777  */
778 static  void    showlist(fiop)
779 struct  friostat        *fiop;
780 {
781         struct  frentry *fp = NULL;
782         int     i, set;
783
784         set = fiop->f_active;
785         if (opts & OPT_INACTIVE)
786                 set = 1 - set;
787         if (opts & OPT_ACCNT) {
788 #ifdef USE_INET6
789                 if ((use_inet6) && (opts & OPT_OUTQUE)) {
790                         i = F_ACOUT;
791                         fp = (struct frentry *)fiop->f_acctout6[set];
792                 } else if ((use_inet6) && (opts & OPT_INQUE)) {
793                         i = F_ACIN;
794                         fp = (struct frentry *)fiop->f_acctin6[set];
795                 } else
796 #endif
797                 if (opts & OPT_OUTQUE) {
798                         i = F_ACOUT;
799                         fp = (struct frentry *)fiop->f_acctout[set];
800                 } else if (opts & OPT_INQUE) {
801                         i = F_ACIN;
802                         fp = (struct frentry *)fiop->f_acctin[set];
803                 } else {
804                         FPRINTF(stderr, "No -i or -o given with -a\n");
805                         return;
806                 }
807         } else {
808 #ifdef  USE_INET6
809                 if ((use_inet6) && (opts & OPT_OUTQUE)) {
810                         i = F_OUT;
811                         fp = (struct frentry *)fiop->f_fout6[set];
812                 } else if ((use_inet6) && (opts & OPT_INQUE)) {
813                         i = F_IN;
814                         fp = (struct frentry *)fiop->f_fin6[set];
815                 } else
816 #endif
817                 if (opts & OPT_OUTQUE) {
818                         i = F_OUT;
819                         fp = (struct frentry *)fiop->f_fout[set];
820                 } else if (opts & OPT_INQUE) {
821                         i = F_IN;
822                         fp = (struct frentry *)fiop->f_fin[set];
823                 } else
824                         return;
825         }
826         if (opts & OPT_VERBOSE)
827                 FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
828
829         if (opts & OPT_VERBOSE)
830                 PRINTF("fp %p set %d\n", fp, set);
831         if (fp == NULL) {
832                 FPRINTF(stderr, "empty list for %s%s\n",
833                         (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]);
834                 return;
835         }
836         printlist(fp);
837 }
838
839
840 /*
841  * Display ipfilter stateful filtering information
842  */
843 static void showipstates(ipsp)
844 ips_stat_t *ipsp;
845 {
846         ipstate_t *istab[IPSTATE_SIZE];
847
848         /*
849          * If a list of states hasn't been asked for, only print out stats
850          */
851         if (!(opts & OPT_SHOWLIST)) {
852                 PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n",
853                         ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp);
854                 PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits,
855                         ipsp->iss_miss);
856                 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu bkts in use\n",
857                         ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse);
858                 PRINTF("\t%lu logged\n\t%lu log failures\n",
859                         ipsp->iss_logged, ipsp->iss_logfail);
860                 PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n",
861                         ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin);
862                 return;
863         }
864
865         if (kmemcpy((char *)istab, (u_long)ipsp->iss_table, sizeof(istab)))
866                 return;
867
868         /*
869          * Print out all the state information currently held in the kernel.
870          */
871         while (ipsp->iss_list != NULL) {
872                 ipsp->iss_list = printstate(ipsp->iss_list, opts);
873         }
874 }
875
876
877 #if SOLARIS
878 /*
879  * Displays the list of interfaces of which IPFilter has taken control in
880  * Solaris.
881  */
882 void showqiflist(kern)
883 char *kern;
884 {
885         struct nlist qifnlist[2] = {
886                 { "_qif_head" },
887                 { NULL }
888         };
889         qif_t qif, *qf;
890         ill_t ill;
891
892         if (kern == NULL)
893                 kern = "/dev/ksyms";
894
895         if (nlist(kern, qifnlist) == -1) {
896                 fprintf(stderr, "nlist error\n");
897                 return;
898         }
899
900         printf("List of interfaces bound by IPFilter:\n");
901         if (kmemcpy((char *)&qf, (u_long)qifnlist[0].n_value, sizeof(qf)))
902                 return;
903         while (qf) {
904                 if (kmemcpy((char *)&qif, (u_long)qf, sizeof(qif)))
905                         break;
906                 if (kmemcpy((char *)&ill, (u_long)qif.qf_ill, sizeof(ill)))
907                         ill.ill_ppa = -1;
908                 printf("Name: %-8s Header Length: %2d SAP: %s (%04x) PPA %d",
909                         qif.qf_name, qif.qf_hl,
910 #ifdef  IP6_DL_SAP
911                         (qif.qf_sap == IP6_DL_SAP) ? "IPv6" : "IPv4"
912 #else
913                         "IPv4"
914 #endif
915                         , qif.qf_sap, ill.ill_ppa);
916                 printf(" %ld %ld", qif.qf_incnt, qif.qf_outcnt);
917                 qf = qif.qf_next;
918                 putchar('\n');
919         }
920 }
921 #endif
922
923
924 #ifdef STATETOP
925 static void topipstates(saddr, daddr, sport, dport, protocol,
926                         refreshtime, topclosed)
927 struct in_addr saddr;
928 struct in_addr daddr;
929 int sport;
930 int dport;
931 int protocol;
932 int refreshtime;
933 int topclosed;
934 {
935         char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
936         int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
937         int i, j, winx, tsentry, maxx, maxy, redraw = 0;
938         ipstate_t *istab[IPSTATE_SIZE], ips;
939         ips_stat_t ipsst, *ipsstp = &ipsst;
940         statetop_t *tstable = NULL, *tp;
941         char hostnm[HOSTNMLEN];
942         struct protoent *proto;
943         int c = 0;
944         time_t t;
945 #ifdef USE_POLL
946         struct pollfd set[1];
947 #else
948         struct timeval selecttimeout; 
949         fd_set readfd;
950 #endif
951
952         /* init ncurses stuff */
953         initscr();
954         cbreak();
955         noecho();
956
957         /* init hostname */
958         gethostname(hostnm, sizeof(hostnm) - 1);
959         hostnm[sizeof(hostnm) - 1] = '\0';
960
961         /* repeat until user aborts */
962         while ( 1 ) {
963
964                 /* get state table */
965                 bzero((char *)&ipsst, sizeof(&ipsst));
966                 if ((ioctl(state_fd, SIOCGETFS, &ipsstp) == -1)) {
967                         perror("ioctl(SIOCGETFS)");
968                         exit(-1);
969                 }
970                 if (kmemcpy((char *)istab, (u_long)ipsstp->iss_table,
971                             sizeof(ips)))
972                         return;
973
974                 /* clear the history */
975                 tsentry = -1;
976
977                 /* read the state table and store in tstable */
978                 while (ipsstp->iss_list) {
979                         if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list,
980                                     sizeof(ips)))
981                                 break;
982                         ipsstp->iss_list = ips.is_next;
983
984                         if (((saddr.s_addr == INADDR_ANY) ||
985                              (saddr.s_addr == ips.is_saddr)) &&
986                             ((daddr.s_addr == INADDR_ANY) ||
987                              (daddr.s_addr == ips.is_daddr)) &&
988                             ((protocol < 0) || (protocol == ips.is_p)) &&
989                             (((ips.is_p != IPPROTO_TCP) &&
990                              (ips.is_p != IPPROTO_UDP)) || 
991                              (((sport < 0) ||
992                                (htons(sport) == ips.is_sport)) &&
993                               ((dport < 0) ||
994                                (htons(dport) == ips.is_dport)))) &&
995                              (topclosed || (ips.is_p != IPPROTO_TCP) ||
996                              (ips.is_state[0] < TCPS_LAST_ACK) ||
997                              (ips.is_state[1] < TCPS_LAST_ACK))) { 
998                                 /*
999                                  * if necessary make room for this state
1000                                  * entry
1001                                  */
1002                                 tsentry++;
1003                                 if (!maxtsentries ||
1004                                     (tsentry == maxtsentries)) {
1005
1006                                         maxtsentries += STGROWSIZE;
1007                                         tstable = realloc(tstable, maxtsentries * sizeof(statetop_t));
1008                                         if (!tstable) {
1009                                                 perror("malloc");
1010                                                 exit(-1);
1011                                         }
1012                                 }
1013
1014                                 /* fill structure */
1015                                 tp = tstable + tsentry;
1016                                 tp->st_src = ips.is_src;
1017                                 tp->st_dst = ips.is_dst;
1018                                 tp->st_p = ips.is_p;
1019                                 tp->st_state[0] = ips.is_state[0];
1020                                 tp->st_state[1] = ips.is_state[1];
1021                                 tp->st_pkts = ips.is_pkts;
1022                                 tp->st_bytes = ips.is_bytes;
1023                                 tp->st_age = ips.is_age;
1024                                 if ((ips.is_p == IPPROTO_TCP) ||
1025                                     (ips.is_p == IPPROTO_UDP)) {
1026                                         tp->st_sport = ips.is_sport;
1027                                         tp->st_dport = ips.is_dport;
1028                                 }
1029
1030                         }
1031                 }
1032
1033
1034                 /* sort the array */
1035                 if (tsentry != -1)
1036                         switch (sorting)
1037                         {
1038                         case STSORT_PR:
1039                                 qsort(tstable, tsentry + 1,
1040                                       sizeof(statetop_t), sort_p);
1041                                 break;
1042                         case STSORT_PKTS:
1043                                 qsort(tstable, tsentry + 1,
1044                                       sizeof(statetop_t), sort_pkts);
1045                                 break;
1046                         case STSORT_BYTES:
1047                                 qsort(tstable, tsentry + 1,
1048                                       sizeof(statetop_t), sort_bytes);
1049                                 break;
1050                         case STSORT_TTL:
1051                                 qsort(tstable, tsentry + 1,
1052                                       sizeof(statetop_t), sort_ttl);
1053                                 break;
1054                         case STSORT_SRCIP:
1055                                 qsort(tstable, tsentry + 1,
1056                                       sizeof(statetop_t), sort_srcip);
1057                                 break;
1058                         case STSORT_DSTIP:
1059                                 qsort(tstable, tsentry + 1,
1060                                       sizeof(statetop_t), sort_dstip);
1061                                 break;
1062                         default:
1063                                 break;
1064                         }
1065
1066                 /* print title */
1067                 erase();
1068                 getmaxyx(stdscr, maxy, maxx);
1069                 attron(A_BOLD);
1070                 winx = 0;
1071                 move(winx,0);
1072                 sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION);
1073                 for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
1074                         printw(" ");
1075                 printw("%s", str1);
1076                 attroff(A_BOLD);
1077
1078                 /* just for fun add a clock */
1079                 move(winx, maxx - 8);
1080                 t = time(NULL);
1081                 strftime(str1, 80, "%T", localtime(&t));
1082                 printw("%s\n", str1);
1083
1084                 /*
1085                  * print the display filters, this is placed in the loop, 
1086                  * because someday I might add code for changing these
1087                  * while the programming is running :-)
1088                  */
1089                 if (sport >= 0)
1090                         sprintf(str1, "%s,%d", inet_ntoa(saddr), sport);
1091                 else
1092                         sprintf(str1, "%s", inet_ntoa(saddr));
1093
1094                 if (dport >= 0)
1095                         sprintf(str2, "%s,%d", inet_ntoa(daddr), dport);
1096                 else
1097                         sprintf(str2, "%s", inet_ntoa(daddr));
1098
1099                 if (protocol < 0)
1100                         strcpy(str3, "any");
1101                 else if ((proto = getprotobynumber(protocol)) != NULL)
1102                         sprintf(str3, "%s", proto->p_name); 
1103                 else
1104                         sprintf(str3, "%d", protocol);
1105
1106                 switch (sorting)
1107                 {
1108                 case STSORT_PR:
1109                         sprintf(str4, "proto");
1110                         break;
1111                 case STSORT_PKTS:
1112                         sprintf(str4, "# pkts");
1113                         break;
1114                 case STSORT_BYTES:
1115                         sprintf(str4, "# bytes");
1116                         break;
1117                 case STSORT_TTL:
1118                         sprintf(str4, "ttl");
1119                         break;
1120                 case STSORT_SRCIP:
1121                         sprintf(str4, "srcip");
1122                         break;
1123                 case STSORT_DSTIP:
1124                         sprintf(str4, "dstip");
1125                         break;
1126                 default:
1127                         sprintf(str4, "unknown");
1128                         break;
1129                 }
1130
1131                 if (reverse)
1132                         strcat(str4, " (reverse)");
1133
1134                 winx += 2;
1135                 move(winx,0);
1136                 printw("Src = %s  Dest = %s  Proto = %s  Sorted by = %s\n\n",
1137                        str1, str2, str3, str4);
1138
1139                 /* print column description */
1140                 winx += 2;
1141                 move(winx,0);
1142                 attron(A_BOLD);
1143                 printw("%-21s %-21s %3s %4s %7s %9s %9s\n", "Source IP",
1144                        "Destination IP", "ST", "PR", "#pkts", "#bytes", "ttl");
1145                 attroff(A_BOLD);
1146
1147                 /* print all the entries */
1148                 tp = tstable;
1149                 if (reverse)
1150                         tp += tsentry;
1151
1152                 if (tsentry > maxy - 6)
1153                         tsentry = maxy - 6;
1154                 for (i = 0; i <= tsentry; i++) {
1155                         /* print src/dest and port */
1156                         if ((tp->st_p == IPPROTO_TCP) ||
1157                             (tp->st_p == IPPROTO_UDP)) {
1158                                 sprintf(str1, "%s,%hu",
1159                                         inet_ntoa(tp->st_src.in4),
1160                                         ntohs(tp->st_sport));
1161                                 sprintf(str2, "%s,%hu",
1162                                         inet_ntoa(tp->st_dst.in4),
1163                                         ntohs(tp->st_dport));
1164                         } else {
1165                                 sprintf(str1, "%s", inet_ntoa(tp->st_src.in4));
1166                                 sprintf(str2, "%s", inet_ntoa(tp->st_dst.in4));
1167                         }
1168                         winx++;
1169                         move(winx, 0);
1170                         printw("%-21s %-21s", str1, str2);
1171
1172                         /* print state */
1173                         sprintf(str1, "%X/%X", tp->st_state[0],
1174                                 tp->st_state[1]);
1175                         printw(" %3s", str1);
1176
1177                         /* print proto */
1178                         proto = getprotobynumber(tp->st_p);
1179                         if (proto) {
1180                                 strncpy(str1, proto->p_name, 4);
1181                                 str1[4] = '\0';
1182                         } else {
1183                                 sprintf(str1, "%d", tp->st_p);
1184                         }
1185                         printw(" %4s", str1);
1186                                 /* print #pkt/#bytes */
1187 #ifdef  USE_QUAD_T
1188                         printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
1189                                 (unsigned long long) tp->st_bytes);
1190 #else
1191                         printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
1192 #endif
1193                         printw(" %9s", ttl_to_string(tp->st_age));
1194
1195                         if (reverse)
1196                                 tp--;
1197                         else
1198                                 tp++;
1199                 }
1200
1201                 /* screen data structure is filled, now update the screen */
1202                 if (redraw)
1203                         clearok(stdscr,1);
1204
1205                 refresh();
1206                 if (redraw) {
1207                         clearok(stdscr,0);
1208                         redraw = 0;
1209                 }
1210
1211                 /* wait for key press or a 1 second time out period */
1212 #ifdef USE_POLL
1213                 set[0].fd = 0;
1214                 set[0].events = POLLIN;
1215                 poll(set, 1, refreshtime * 1000);
1216
1217                 /* if key pressed, read all waiting keys */
1218                 if (set[0].revents & POLLIN)
1219 #else
1220                 selecttimeout.tv_sec = refreshtime;
1221                 selecttimeout.tv_usec = 0;
1222                 FD_ZERO(&readfd);
1223                 FD_SET(0, &readfd);
1224                 select(1, &readfd, NULL, NULL, &selecttimeout);
1225
1226                 /* if key pressed, read all waiting keys */
1227                 if (FD_ISSET(0, &readfd))
1228 #endif
1229
1230                 {
1231                         c = wgetch(stdscr);
1232                         if (c == ERR)
1233                                 continue;
1234
1235                         if (isalpha(c) && isupper(c))
1236                                 c = tolower(c);
1237                         if (c == 'l') {
1238                                 redraw = 1;
1239                         } else if (c == 'q') {
1240                                 break;  /* exits while() loop */
1241                         } else if (c == 'r') {
1242                                 reverse = !reverse;
1243                         } else if (c == 's') {
1244                                 sorting++;
1245                                 if (sorting > STSORT_MAX)
1246                                         sorting = 0;
1247                         }
1248                 }
1249         } /* while */
1250
1251         printw("\n");
1252         nocbreak();
1253         endwin();
1254 }
1255 #endif
1256
1257
1258 /*
1259  * Show fragment cache information that's held in the kernel.
1260  */
1261 static void showfrstates(ifsp)
1262 ipfrstat_t *ifsp;
1263 {
1264         struct ipfr *ipfrtab[IPFT_SIZE], ifr;
1265         frentry_t fr;
1266         int i;
1267
1268         /*
1269          * print out the numeric statistics
1270          */
1271         PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n",
1272                 ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
1273         PRINTF("\t%lu no memory\n\t%lu already exist\n",
1274                 ifsp->ifs_nomem, ifsp->ifs_exists);
1275         PRINTF("\t%lu inuse\n", ifsp->ifs_inuse);
1276         if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab)))
1277                 return;
1278
1279         /*
1280          * Print out the contents (if any) of the fragment cache table.
1281          */
1282         PRINTF("\n");
1283         for (i = 0; i < IPFT_SIZE; i++)
1284                 while (ipfrtab[i]) {
1285                         if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1286                                     sizeof(ifr)) == -1)
1287                                 break;
1288                         PRINTF("%s -> ", hostname(4, &ifr.ipfr_src));
1289                         if (kmemcpy((char *)&fr, (u_long)ifr.ipfr_rule,
1290                                     sizeof(fr)) == -1)
1291                                 break; 
1292                         PRINTF("%s id %d ttl %d pr %d seen0 %d ifp %p tos %#02x = fl %#x\n",
1293                                 hostname(4, &ifr.ipfr_dst), ntohs(ifr.ipfr_id),
1294                                 ifr.ipfr_ttl, ifr.ipfr_p, ifr.ipfr_seen0, 
1295                                 ifr.ipfr_ifp, ifr.ipfr_tos, fr.fr_flags);
1296                         ipfrtab[i] = ifr.ipfr_next;
1297                 }
1298         if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,sizeof(ipfrtab)))
1299                 return;
1300         for (i = 0; i < IPFT_SIZE; i++)
1301                 while (ipfrtab[i]) {
1302                         if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1303                                     sizeof(ifr)) == -1)
1304                                 break;
1305                         PRINTF("NAT: %s -> ", hostname(4, &ifr.ipfr_src));
1306                         if (kmemcpy((char *)&fr, (u_long)ifr.ipfr_rule,
1307                                     sizeof(fr)) == -1)
1308                                 break;
1309                         PRINTF("%s %d %d %d %#02x = %#x\n",
1310                                 hostname(4, &ifr.ipfr_dst), ifr.ipfr_id,
1311                                 ifr.ipfr_ttl, ifr.ipfr_p, ifr.ipfr_tos,
1312                                 fr.fr_flags);
1313                         ipfrtab[i] = ifr.ipfr_next;
1314                 }
1315 }
1316
1317
1318 /*
1319  * Show stats on how auth within IPFilter has been used
1320  */
1321 static void showauthstates(asp)
1322 fr_authstat_t *asp;
1323 {
1324         frauthent_t *frap, fra;
1325
1326 #ifdef  USE_QUAD_T
1327         printf("Authorisation hits: %qu\tmisses %qu\n",
1328                 (unsigned long long) asp->fas_hits,
1329                 (unsigned long long) asp->fas_miss);
1330 #else
1331         printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
1332                 asp->fas_miss);
1333 #endif
1334         printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
1335                 asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
1336                 asp->fas_sendok);
1337         printf("queok %ld\nquefail %ld\nexpire %ld\n",
1338                 asp->fas_queok, asp->fas_quefail, asp->fas_expire);
1339
1340         frap = asp->fas_faelist;
1341         while (frap) {
1342                 if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1)
1343                         break;
1344
1345                 printf("age %ld\t", fra.fae_age);
1346                 printfr(&fra.fae_fr);
1347                 frap = fra.fae_next;
1348         }
1349 }
1350
1351
1352 /*
1353  * Display groups used for each of filter rules, accounting rules and
1354  * authentication, separately.
1355  */
1356 static void showgroups(fiop)
1357 struct friostat *fiop;
1358 {
1359         static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
1360         frgroup_t *fp, grp;
1361         int on, off, i;
1362
1363         on = fiop->f_active;
1364         off = 1 - on;
1365
1366         for (i = 0; i < 3; i++) {
1367                 printf("%s groups (active):\n", gnames[i]);
1368                 for (fp = fiop->f_groups[i][on]; fp; fp = grp.fg_next)
1369                         if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1370                                 break;
1371                         else
1372                                 printf("%hu\n", grp.fg_num);
1373                 printf("%s groups (inactive):\n", gnames[i]);
1374                 for (fp = fiop->f_groups[i][off]; fp; fp = grp.fg_next)
1375                         if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1376                                 break;
1377                         else
1378                                 printf("%hu\n", grp.fg_num);
1379         }
1380 }
1381
1382 static void parse_ipportstr(argument, ip, port)
1383 const char *argument;
1384 struct in_addr *ip;
1385 int *port;
1386 {
1387
1388         char *s, *comma;
1389
1390         /* make working copy of argument, Theoretically you must be able
1391          * to write to optarg, but that seems very ugly to me....
1392          */
1393         if ((s = malloc(strlen(argument) + 1)) == NULL)
1394                 perror("malloc");
1395         strcpy(s, argument);
1396
1397         /* get port */
1398         if ((comma = strchr(s, ',')) != NULL) {
1399                 if (!strcasecmp(s, "any")) {
1400                         *port = -1;
1401                 } else if (!sscanf(comma + 1, "%d", port) ||
1402                            (*port < 0) || (*port > 65535)) {
1403                         fprintf(stderr, "Invalid port specfication in %s\n",
1404                                 argument);
1405                         exit(-2);
1406                 }
1407                 *comma = '\0';
1408         }
1409
1410
1411         /* get ip address */
1412         if (!strcasecmp(s, "any")) {
1413                 ip->s_addr = INADDR_ANY;
1414         } else  if (!inet_aton(s, ip)) {
1415                 fprintf(stderr, "Invalid IP address: %s\n", s);
1416                 exit(-2);
1417         }
1418
1419         /* free allocated memory */
1420         free(s);
1421 }
1422
1423
1424 #ifdef STATETOP
1425 static char ttlbuf[STSTRSIZE];
1426
1427 static char *ttl_to_string(ttl)
1428 long int ttl;
1429 {
1430
1431         int hours, minutes, seconds;
1432
1433         /* ttl is in half seconds */
1434         ttl /= 2;
1435
1436         hours = ttl / 3600;
1437         ttl = ttl % 3600;
1438         minutes = ttl / 60;
1439         seconds = ttl % 60;
1440
1441         if (hours > 0 )
1442                 sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds);
1443         else
1444                 sprintf(ttlbuf, "%2d:%02d", minutes, seconds);
1445         return ttlbuf;
1446 }
1447
1448
1449 static int sort_pkts(a, b)
1450 const void *a;
1451 const void *b;
1452 {
1453
1454         register const statetop_t *ap = a;
1455         register const statetop_t *bp = b;
1456
1457         if (ap->st_pkts == bp->st_pkts)
1458                 return 0;
1459         else if (ap->st_pkts < bp->st_pkts)
1460                 return 1;
1461         return -1;
1462 }
1463
1464
1465 static int sort_bytes(a, b)
1466 const void *a;
1467 const void *b;
1468 {
1469         register const statetop_t *ap = a;
1470         register const statetop_t *bp = b;
1471
1472         if (ap->st_bytes == bp->st_bytes)
1473                 return 0;
1474         else if (ap->st_bytes < bp->st_bytes)
1475                 return 1;
1476         return -1;
1477 }
1478
1479
1480 static int sort_p(a, b)
1481 const void *a;
1482 const void *b;
1483 {
1484         register const statetop_t *ap = a;
1485         register const statetop_t *bp = b;
1486
1487         if (ap->st_p == bp->st_p)
1488                 return 0;
1489         else if (ap->st_p < bp->st_p)
1490                 return 1;
1491         return -1;
1492 }
1493
1494
1495 static int sort_ttl(a, b)
1496 const void *a;
1497 const void *b;
1498 {
1499         register const statetop_t *ap = a;
1500         register const statetop_t *bp = b;
1501
1502         if (ap->st_age == bp->st_age)
1503                 return 0;
1504         else if (ap->st_age < bp->st_age)
1505                 return 1;
1506         return -1;
1507 }
1508
1509 static int sort_srcip(a, b)
1510 const void *a;
1511 const void *b;
1512 {
1513         register const statetop_t *ap = a;
1514         register const statetop_t *bp = b;
1515
1516         if (ntohl(ap->st_src.in4.s_addr) == ntohl(bp->st_src.in4.s_addr))
1517                 return 0;
1518         else if (ntohl(ap->st_src.in4.s_addr) > ntohl(bp->st_src.in4.s_addr))
1519                 return 1;
1520         return -1;
1521 }
1522
1523 static int sort_dstip(a, b)
1524 const void *a;
1525 const void *b;
1526 {
1527         register const statetop_t *ap = a;
1528         register const statetop_t *bp = b;
1529
1530         if (ntohl(ap->st_dst.in4.s_addr) == ntohl(bp->st_dst.in4.s_addr))
1531                 return 0;
1532         else if (ntohl(ap->st_dst.in4.s_addr) > ntohl(bp->st_dst.in4.s_addr))
1533                 return 1;
1534         return -1;
1535 }
1536 #endif