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