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