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