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