1 /* $NetBSD: ipfstat.c,v 1.6 2018/02/04 08:19:42 mrg Exp $ */
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 __attribute__((__used__)) const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed";
75 static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ipfstat.c,v 1.1.1.2 2012/07/22 13:44:55 darrenr";
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 ipfobj_t obj;
803 void *buf;
804 size_t bufsiz;
805 int rules;
806 int num;
807
808 rules = 0;
809
810 rule.iri_inout = out;
811 rule.iri_active = set;
812 rule.iri_rule = &fb;
813 rule.iri_nrules = 1;
814 if (group != NULL)
815 strncpy(rule.iri_group, group, FR_GROUPLEN);
816 else
817 rule.iri_group[0] = '\0';
818
819 bzero((char *)&zero, sizeof(zero));
820
821 bzero((char *)&obj, sizeof(obj));
822 obj.ipfo_rev = IPFILTER_VERSION;
823 obj.ipfo_type = IPFOBJ_IPFITER;
824 obj.ipfo_size = sizeof(rule);
825 obj.ipfo_ptr = &rule;
826
827 /*
828 * The API does not know how much we need for filter data. Assume
829 * 10K is large enough. XXX: The code silently fails elsewhere on
830 * allocation, we do the same here.
831 */
832 if ((buf = malloc(bufsiz = sizeof(*fp) + 10240)) == NULL)
833 return 0;
834
835 while (rule.iri_rule != NULL) {
836 memset(buf, 0xff, bufsiz);
837 fp = buf;
838 rule.iri_rule = fp;
839 if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) {
840 ipferror(ipf_fd, "ioctl(SIOCIPFITER)");
841 num = IPFGENITER_IPF;
842 (void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
843 return rules;
844 }
845 if (bcmp(fp, &zero, sizeof(zero)) == 0)
846 break;
847 if (rule.iri_rule == NULL)
848 break;
849 #ifdef USE_INET6
850 if (use_inet6 != 0) {
851 if (fp->fr_family != 0 && fp->fr_family != AF_INET6)
852 continue;
853 } else
854 #endif
855 {
856 if (fp->fr_family != 0 && fp->fr_family != AF_INET)
857 continue;
858 }
859 if (fp->fr_data != NULL) {
860 fp->fr_data = calloc(1, fp->fr_dsize);
861 if (fp->fr_data != NULL) {
862 memcpy(fp->fr_data, (char *)fp + fp->fr_size,
863 fp->fr_dsize);
864 }
865 }
866
867 rules++;
868
869 if (opts & (OPT_HITS|OPT_DEBUG))
870 #ifdef USE_QUAD_T
871 PRINTF("%llu ", (unsigned long long) fp->fr_hits);
872 #else
873 PRINTF("%lu ", fp->fr_hits);
874 #endif
875 if (opts & (OPT_ACCNT|OPT_DEBUG))
876 #ifdef USE_QUAD_T
877 PRINTF("%llu ", (unsigned long long) fp->fr_bytes);
878 #else
879 PRINTF("%lu ", fp->fr_bytes);
880 #endif
881 if (opts & OPT_SHOWLINENO)
882 PRINTF("@%d ", rules);
883
884 if (fp->fr_die != 0)
885 fp->fr_die -= fiop->f_ticks;
886
887 printfr(fp, ioctl);
888 if (opts & OPT_DEBUG) {
889 binprint(fp, fp->fr_size);
890 if (fp->fr_data != NULL && fp->fr_dsize > 0)
891 binprint(fp->fr_data, fp->fr_dsize);
892 }
893 if (fp->fr_type == FR_T_CALLFUNC) {
894 rules += printlivelist(fiop, out, set, fp->fr_data,
895 group, "# callfunc: ");
896 }
897 }
898
899 num = IPFGENITER_IPF;
900 (void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
901
902 return rules;
903 }
904
905
printdeadlist(fiop,out,set,fp,group,comment)906 static void printdeadlist(fiop, out, set, fp, group, comment)
907 friostat_t *fiop;
908 int out, set;
909 frentry_t *fp;
910 char *group, *comment;
911 {
912 frgroup_t *grtop, *grtail, *g;
913 struct frentry fb;
914 char *data;
915 u_32_t type;
916 int n;
917
918 fb.fr_next = fp;
919 n = 0;
920 grtop = NULL;
921 grtail = NULL;
922
923 for (n = 1; fp; fp = fb.fr_next, n++) {
924 if (kmemcpy((char *)&fb, (u_long)fb.fr_next,
925 fb.fr_size) == -1) {
926 perror("kmemcpy");
927 return;
928 }
929 fp = &fb;
930 if (use_inet6 != 0) {
931 if (fp->fr_family != 0 && fp->fr_family != 6)
932 continue;
933 } else {
934 if (fp->fr_family != 0 && fp->fr_family != 4)
935 continue;
936 }
937
938 data = NULL;
939 type = fb.fr_type & ~FR_T_BUILTIN;
940 if (type == FR_T_IPF || type == FR_T_BPFOPC) {
941 if (fb.fr_dsize) {
942 data = malloc(fb.fr_dsize);
943
944 if (kmemcpy(data, (u_long)fb.fr_data,
945 fb.fr_dsize) == -1) {
946 perror("kmemcpy");
947 return;
948 }
949 fb.fr_data = data;
950 }
951 }
952
953 if (opts & OPT_HITS)
954 #ifdef USE_QUAD_T
955 PRINTF("%llu ", (unsigned long long) fb.fr_hits);
956 #else
957 PRINTF("%lu ", fb.fr_hits);
958 #endif
959 if (opts & OPT_ACCNT)
960 #ifdef USE_QUAD_T
961 PRINTF("%llu ", (unsigned long long) fb.fr_bytes);
962 #else
963 PRINTF("%lu ", fb.fr_bytes);
964 #endif
965 if (opts & OPT_SHOWLINENO)
966 PRINTF("@%d ", n);
967
968 printfr(fp, ioctl);
969 if (opts & OPT_DEBUG) {
970 binprint(fp, fp->fr_size);
971 if (fb.fr_data != NULL && fb.fr_dsize > 0)
972 binprint(fb.fr_data, fb.fr_dsize);
973 }
974 if (data != NULL)
975 free(data);
976 if (fb.fr_grhead != -1) {
977 g = calloc(1, sizeof(*g));
978
979 if (g != NULL) {
980 strncpy(g->fg_name, fb.fr_names + fb.fr_grhead,
981 FR_GROUPLEN);
982 if (grtop == NULL) {
983 grtop = g;
984 grtail = g;
985 } else {
986 grtail->fg_next = g;
987 grtail = g;
988 }
989 }
990 }
991 if (type == FR_T_CALLFUNC) {
992 printdeadlist(fiop, out, set, fb.fr_data, group,
993 "# callfunc: ");
994 }
995 }
996
997 while ((g = grtop) != NULL) {
998 printdeadlist(fiop, out, set, NULL, g->fg_name, comment);
999 grtop = g->fg_next;
1000 free(g);
1001 }
1002 }
1003
1004 /*
1005 * print out all of the asked for rule sets, using the stats struct as
1006 * the base from which to get the pointers.
1007 */
showlist(fiop)1008 static void showlist(fiop)
1009 struct friostat *fiop;
1010 {
1011 struct frentry *fp = NULL;
1012 int i, set;
1013
1014 set = fiop->f_active;
1015 if (opts & OPT_INACTIVE)
1016 set = 1 - set;
1017 if (opts & OPT_ACCNT) {
1018 if (opts & OPT_OUTQUE) {
1019 i = F_ACOUT;
1020 fp = (struct frentry *)fiop->f_acctout[set];
1021 } else if (opts & OPT_INQUE) {
1022 i = F_ACIN;
1023 fp = (struct frentry *)fiop->f_acctin[set];
1024 } else {
1025 FPRINTF(stderr, "No -i or -o given with -a\n");
1026 return;
1027 }
1028 } else {
1029 if (opts & OPT_OUTQUE) {
1030 i = F_OUT;
1031 fp = (struct frentry *)fiop->f_fout[set];
1032 } else if (opts & OPT_INQUE) {
1033 i = F_IN;
1034 fp = (struct frentry *)fiop->f_fin[set];
1035 } else
1036 return;
1037 }
1038 if (opts & OPT_DEBUG)
1039 FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
1040
1041 if (opts & OPT_DEBUG)
1042 PRINTF("fp %p set %d\n", fp, set);
1043
1044 if (live_kernel == 1) {
1045 int printed;
1046
1047 printed = printlivelist(fiop, i, set, fp, NULL, NULL);
1048 if (printed == 0) {
1049 FPRINTF(stderr, "# empty list for %s%s\n",
1050 (opts & OPT_INACTIVE) ? "inactive " : "",
1051 filters[i]);
1052 }
1053 } else {
1054 if (!fp) {
1055 FPRINTF(stderr, "# empty list for %s%s\n",
1056 (opts & OPT_INACTIVE) ? "inactive " : "",
1057 filters[i]);
1058 } else {
1059 printdeadlist(fiop, i, set, fp, NULL, NULL);
1060 }
1061 }
1062 }
1063
1064
1065 /*
1066 * Display ipfilter stateful filtering information
1067 */
showipstates(ipsp,filter)1068 static void showipstates(ipsp, filter)
1069 ips_stat_t *ipsp;
1070 int *filter;
1071 {
1072 ipstate_t *is;
1073 int i;
1074
1075 /*
1076 * If a list of states hasn't been asked for, only print out stats
1077 */
1078 if (!(opts & OPT_SHOWLIST)) {
1079 showstatestats(ipsp);
1080 return;
1081 }
1082
1083 if ((state_fields != NULL) && (nohdrfields == 0)) {
1084 for (i = 0; state_fields[i].w_value != 0; i++) {
1085 printfieldhdr(statefields, state_fields + i);
1086 if (state_fields[i + 1].w_value != 0)
1087 printf("\t");
1088 }
1089 printf("\n");
1090 }
1091
1092 /*
1093 * Print out all the state information currently held in the kernel.
1094 */
1095 for (is = ipsp->iss_list; is != NULL; ) {
1096 ipstate_t ips;
1097
1098 is = fetchstate(is, &ips);
1099
1100 if (is == NULL)
1101 break;
1102
1103 is = ips.is_next;
1104 if ((filter != NULL) &&
1105 (state_matcharray(&ips, filter) == 0)) {
1106 continue;
1107 }
1108 if (state_fields != NULL) {
1109 for (i = 0; state_fields[i].w_value != 0; i++) {
1110 printstatefield(&ips, state_fields[i].w_value);
1111 if (state_fields[i + 1].w_value != 0)
1112 printf("\t");
1113 }
1114 printf("\n");
1115 } else {
1116 printstate(&ips, opts, ipsp->iss_ticks);
1117 }
1118 }
1119 }
1120
1121
showstatestats(ipsp)1122 static void showstatestats(ipsp)
1123 ips_stat_t *ipsp;
1124 {
1125 int minlen, maxlen, totallen;
1126 ipftable_t table;
1127 u_int *buckets;
1128 ipfobj_t obj;
1129 int i, sz;
1130
1131 /*
1132 * If a list of states hasn't been asked for, only print out stats
1133 */
1134
1135 sz = sizeof(*buckets) * ipsp->iss_state_size;
1136 buckets = (u_int *)malloc(sz);
1137
1138 obj.ipfo_rev = IPFILTER_VERSION;
1139 obj.ipfo_type = IPFOBJ_GTABLE;
1140 obj.ipfo_size = sizeof(table);
1141 obj.ipfo_ptr = &table;
1142
1143 table.ita_type = IPFTABLE_BUCKETS;
1144 table.ita_table = buckets;
1145
1146 if (live_kernel == 1) {
1147 if (ioctl(state_fd, SIOCGTABL, &obj) != 0) {
1148 free(buckets);
1149 return;
1150 }
1151 } else {
1152 if (kmemcpy((char *)buckets,
1153 (u_long)ipsp->iss_bucketlen, sz)) {
1154 free(buckets);
1155 return;
1156 }
1157 }
1158
1159 PRINTF("%u\tactive state table entries\n",ipsp->iss_active);
1160 PRINTF("%lu\tadd bad\n", ipsp->iss_add_bad);
1161 PRINTF("%lu\tadd duplicate\n", ipsp->iss_add_dup);
1162 PRINTF("%lu\tadd locked\n", ipsp->iss_add_locked);
1163 PRINTF("%lu\tadd oow\n", ipsp->iss_add_oow);
1164 PRINTF("%lu\tbucket full\n", ipsp->iss_bucket_full);
1165 PRINTF("%lu\tcheck bad\n", ipsp->iss_check_bad);
1166 PRINTF("%lu\tcheck miss\n", ipsp->iss_check_miss);
1167 PRINTF("%lu\tcheck nattag\n", ipsp->iss_check_nattag);
1168 PRINTF("%lu\tclone nomem\n", ipsp->iss_clone_nomem);
1169 PRINTF("%lu\tcheck notag\n", ipsp->iss_check_notag);
1170 PRINTF("%lu\tcheck success\n", ipsp->iss_hits);
1171 PRINTF("%lu\tcloned\n", ipsp->iss_cloned);
1172 PRINTF("%lu\texpired\n", ipsp->iss_expire);
1173 PRINTF("%lu\tflush all\n", ipsp->iss_flush_all);
1174 PRINTF("%lu\tflush closing\n", ipsp->iss_flush_closing);
1175 PRINTF("%lu\tflush queue\n", ipsp->iss_flush_queue);
1176 PRINTF("%lu\tflush state\n", ipsp->iss_flush_state);
1177 PRINTF("%lu\tflush timeout\n", ipsp->iss_flush_timeout);
1178 PRINTF("%u\thash buckets in use\n", ipsp->iss_inuse);
1179 PRINTF("%lu\tICMP bad\n", ipsp->iss_icmp_bad);
1180 PRINTF("%lu\tICMP banned\n", ipsp->iss_icmp_banned);
1181 PRINTF("%lu\tICMP errors\n", ipsp->iss_icmp_icmperr);
1182 PRINTF("%lu\tICMP head block\n", ipsp->iss_icmp_headblock);
1183 PRINTF("%lu\tICMP hits\n", ipsp->iss_icmp_hits);
1184 PRINTF("%lu\tICMP not query\n", ipsp->iss_icmp_notquery);
1185 PRINTF("%lu\tICMP short\n", ipsp->iss_icmp_short);
1186 PRINTF("%lu\tICMP too many\n", ipsp->iss_icmp_toomany);
1187 PRINTF("%lu\tICMPv6 errors\n", ipsp->iss_icmp6_icmperr);
1188 PRINTF("%lu\tICMPv6 miss\n", ipsp->iss_icmp6_miss);
1189 PRINTF("%lu\tICMPv6 not info\n", ipsp->iss_icmp6_notinfo);
1190 PRINTF("%lu\tICMPv6 not query\n", ipsp->iss_icmp6_notquery);
1191 PRINTF("%lu\tlog fail\n", ipsp->iss_log_fail);
1192 PRINTF("%lu\tlog ok\n", ipsp->iss_log_ok);
1193 PRINTF("%lu\tlookup interface mismatch\n", ipsp->iss_lookup_badifp);
1194 PRINTF("%lu\tlookup mask mismatch\n", ipsp->iss_miss_mask);
1195 PRINTF("%lu\tlookup port mismatch\n", ipsp->iss_lookup_badport);
1196 PRINTF("%lu\tlookup miss\n", ipsp->iss_lookup_miss);
1197 PRINTF("%lu\tmaximum rule references\n", ipsp->iss_max_ref);
1198 PRINTF("%lu\tmaximum hosts per rule\n", ipsp->iss_max_track);
1199 PRINTF("%lu\tno memory\n", ipsp->iss_nomem);
1200 PRINTF("%lu\tout of window\n", ipsp->iss_oow);
1201 PRINTF("%lu\torphans\n", ipsp->iss_orphan);
1202 PRINTF("%lu\tscan block\n", ipsp->iss_scan_block);
1203 PRINTF("%lu\tstate table maximum reached\n", ipsp->iss_max);
1204 PRINTF("%lu\tTCP closing\n", ipsp->iss_tcp_closing);
1205 PRINTF("%lu\tTCP OOW\n", ipsp->iss_tcp_oow);
1206 PRINTF("%lu\tTCP RST add\n", ipsp->iss_tcp_rstadd);
1207 PRINTF("%lu\tTCP too small\n", ipsp->iss_tcp_toosmall);
1208 PRINTF("%lu\tTCP bad options\n", ipsp->iss_tcp_badopt);
1209 PRINTF("%lu\tTCP removed\n", ipsp->iss_fin);
1210 PRINTF("%lu\tTCP FSM\n", ipsp->iss_tcp_fsm);
1211 PRINTF("%lu\tTCP strict\n", ipsp->iss_tcp_strict);
1212 PRINTF("%lu\tTCP wild\n", ipsp->iss_wild);
1213 PRINTF("%lu\tMicrosoft Windows SACK\n", ipsp->iss_winsack);
1214
1215 PRINTF("State logging %sabled\n", state_logging ? "en" : "dis");
1216
1217 PRINTF("IP states added:\n");
1218 for (i = 0; i < 256; i++) {
1219 if (ipsp->iss_proto[i] != 0) {
1220 struct protoent *proto;
1221
1222 proto = getprotobynumber(i);
1223 PRINTF("%lu", ipsp->iss_proto[i]);
1224 if (proto != NULL)
1225 PRINTF("\t%s\n", proto->p_name);
1226 else
1227 PRINTF("\t%d\n", i);
1228 }
1229 }
1230
1231 PRINTF("\nState table bucket statistics:\n");
1232 PRINTF("%u\tin use\n", ipsp->iss_inuse);
1233
1234 minlen = ipsp->iss_max;
1235 totallen = 0;
1236 maxlen = 0;
1237
1238 for (i = 0; i < ipsp->iss_state_size; i++) {
1239 if (buckets[i] > maxlen)
1240 maxlen = buckets[i];
1241 if (buckets[i] < minlen)
1242 minlen = buckets[i];
1243 totallen += buckets[i];
1244 }
1245
1246 PRINTF("%d\thash efficiency\n",
1247 totallen ? ipsp->iss_inuse * 100 / totallen : 0);
1248 PRINTF("%2.2f%%\tbucket usage\n%u\tminimal length\n",
1249 ((float)ipsp->iss_inuse / ipsp->iss_state_size) * 100.0,
1250 minlen);
1251 PRINTF("%u\tmaximal length\n%.3f\taverage length\n",
1252 maxlen,
1253 ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse :
1254 0.0);
1255
1256 #define ENTRIES_PER_LINE 5
1257
1258 if (opts & OPT_VERBOSE) {
1259 PRINTF("\nCurrent bucket sizes :\n");
1260 for (i = 0; i < ipsp->iss_state_size; i++) {
1261 if ((i % ENTRIES_PER_LINE) == 0)
1262 PRINTF("\t");
1263 PRINTF("%4d -> %4u", i, buckets[i]);
1264 if ((i % ENTRIES_PER_LINE) ==
1265 (ENTRIES_PER_LINE - 1))
1266 PRINTF("\n");
1267 else
1268 PRINTF(" ");
1269 }
1270 PRINTF("\n");
1271 }
1272 PRINTF("\n");
1273
1274 free(buckets);
1275
1276 if (live_kernel == 1) {
1277 showtqtable_live(state_fd);
1278 } else {
1279 printtqtable(ipsp->iss_tcptab);
1280 }
1281 }
1282
1283
1284 #ifdef STATETOP
1285 static int handle_resize = 0, handle_break = 0;
1286
topipstates(saddr,daddr,sport,dport,protocol,ver,refreshtime,topclosed,filter)1287 static void topipstates(saddr, daddr, sport, dport, protocol, ver,
1288 refreshtime, topclosed, filter)
1289 i6addr_t saddr;
1290 i6addr_t daddr;
1291 int sport;
1292 int dport;
1293 int protocol;
1294 int ver;
1295 int refreshtime;
1296 int topclosed;
1297 int *filter;
1298 {
1299 char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
1300 int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
1301 int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0;
1302 int len, srclen, dstlen, forward = 1, c = 0;
1303 ips_stat_t ipsst, *ipsstp = &ipsst;
1304 int token_type = IPFGENITER_STATE;
1305 statetop_t *tstable = NULL, *tp;
1306 const char *errstr = "";
1307 ipstate_t ips;
1308 ipfobj_t ipfo;
1309 struct timeval selecttimeout;
1310 char hostnm[HOSTNMLEN];
1311 struct protoent *proto;
1312 fd_set readfd;
1313 time_t t;
1314
1315 /* install signal handlers */
1316 signal(SIGINT, sig_break);
1317 signal(SIGQUIT, sig_break);
1318 signal(SIGTERM, sig_break);
1319 signal(SIGWINCH, sig_resize);
1320
1321 /* init ncurses stuff */
1322 initscr();
1323 cbreak();
1324 noecho();
1325 curs_set(0);
1326 timeout(0);
1327 getmaxyx(stdscr, maxy, maxx);
1328
1329 /* init hostname */
1330 gethostname(hostnm, sizeof(hostnm) - 1);
1331 hostnm[sizeof(hostnm) - 1] = '\0';
1332
1333 /* init ipfobj_t stuff */
1334 bzero((caddr_t)&ipfo, sizeof(ipfo));
1335 ipfo.ipfo_rev = IPFILTER_VERSION;
1336 ipfo.ipfo_type = IPFOBJ_STATESTAT;
1337 ipfo.ipfo_size = sizeof(*ipsstp);
1338 ipfo.ipfo_ptr = (void *)ipsstp;
1339
1340 /* repeat until user aborts */
1341 while ( 1 ) {
1342
1343 /* get state table */
1344 bzero((char *)&ipsst, sizeof(ipsst));
1345 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
1346 errstr = "ioctl(SIOCGETFS)";
1347 ret = -1;
1348 goto out;
1349 }
1350
1351 /* clear the history */
1352 tsentry = -1;
1353
1354 /* reset max str len */
1355 srclen = dstlen = 0;
1356
1357 /* read the state table and store in tstable */
1358 for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
1359
1360 ipsstp->iss_list = fetchstate(ipsstp->iss_list, &ips);
1361 if (ipsstp->iss_list == NULL)
1362 break;
1363
1364 if (ips.is_v != ver)
1365 continue;
1366
1367 if ((filter != NULL) &&
1368 (state_matcharray(&ips, filter) == 0))
1369 continue;
1370
1371 /* check v4 src/dest addresses */
1372 if (ips.is_v == 4) {
1373 if ((saddr.in4.s_addr != INADDR_ANY &&
1374 saddr.in4.s_addr != ips.is_saddr) ||
1375 (daddr.in4.s_addr != INADDR_ANY &&
1376 daddr.in4.s_addr != ips.is_daddr))
1377 continue;
1378 }
1379 #ifdef USE_INET6
1380 /* check v6 src/dest addresses */
1381 if (ips.is_v == 6) {
1382 if ((IP6_NEQ(&saddr, &in6addr_any) &&
1383 IP6_NEQ(&saddr, &ips.is_src)) ||
1384 (IP6_NEQ(&daddr, &in6addr_any) &&
1385 IP6_NEQ(&daddr, &ips.is_dst)))
1386 continue;
1387 }
1388 #endif
1389 /* check protocol */
1390 if (protocol > 0 && protocol != ips.is_p)
1391 continue;
1392
1393 /* check ports if protocol is TCP or UDP */
1394 if (((ips.is_p == IPPROTO_TCP) ||
1395 (ips.is_p == IPPROTO_UDP)) &&
1396 (((sport > 0) && (htons(sport) != ips.is_sport)) ||
1397 ((dport > 0) && (htons(dport) != ips.is_dport))))
1398 continue;
1399
1400 /* show closed TCP sessions ? */
1401 if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
1402 (ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
1403 (ips.is_state[1] >= IPF_TCPS_LAST_ACK))
1404 continue;
1405
1406 /*
1407 * if necessary make room for this state
1408 * entry
1409 */
1410 tsentry++;
1411 if (!maxtsentries || tsentry == maxtsentries) {
1412 maxtsentries += STGROWSIZE;
1413 tstable = realloc(tstable,
1414 maxtsentries * sizeof(statetop_t));
1415 if (tstable == NULL) {
1416 perror("realloc");
1417 exit(-1);
1418 }
1419 }
1420
1421 /* get max src/dest address string length */
1422 len = strlen(getip(ips.is_v, &ips.is_src));
1423 if (srclen < len)
1424 srclen = len;
1425 len = strlen(getip(ips.is_v, &ips.is_dst));
1426 if (dstlen < len)
1427 dstlen = len;
1428
1429 /* fill structure */
1430 tp = tstable + tsentry;
1431 tp->st_src = ips.is_src;
1432 tp->st_dst = ips.is_dst;
1433 tp->st_p = ips.is_p;
1434 tp->st_v = ips.is_v;
1435 tp->st_state[0] = ips.is_state[0];
1436 tp->st_state[1] = ips.is_state[1];
1437 if (forward) {
1438 tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
1439 tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
1440 } else {
1441 tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3];
1442 tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3];
1443 }
1444 tp->st_age = ips.is_die - ipsstp->iss_ticks;
1445 if ((ips.is_p == IPPROTO_TCP) ||
1446 (ips.is_p == IPPROTO_UDP)) {
1447 tp->st_sport = ips.is_sport;
1448 tp->st_dport = ips.is_dport;
1449 }
1450 }
1451
1452 (void) ioctl(state_fd, SIOCIPFDELTOK, &token_type);
1453
1454 /* sort the array */
1455 if (tsentry != -1) {
1456 switch (sorting)
1457 {
1458 case STSORT_PR:
1459 qsort(tstable, tsentry + 1,
1460 sizeof(statetop_t), sort_p);
1461 break;
1462 case STSORT_PKTS:
1463 qsort(tstable, tsentry + 1,
1464 sizeof(statetop_t), sort_pkts);
1465 break;
1466 case STSORT_BYTES:
1467 qsort(tstable, tsentry + 1,
1468 sizeof(statetop_t), sort_bytes);
1469 break;
1470 case STSORT_TTL:
1471 qsort(tstable, tsentry + 1,
1472 sizeof(statetop_t), sort_ttl);
1473 break;
1474 case STSORT_SRCIP:
1475 qsort(tstable, tsentry + 1,
1476 sizeof(statetop_t), sort_srcip);
1477 break;
1478 case STSORT_SRCPT:
1479 qsort(tstable, tsentry +1,
1480 sizeof(statetop_t), sort_srcpt);
1481 break;
1482 case STSORT_DSTIP:
1483 qsort(tstable, tsentry + 1,
1484 sizeof(statetop_t), sort_dstip);
1485 break;
1486 case STSORT_DSTPT:
1487 qsort(tstable, tsentry + 1,
1488 sizeof(statetop_t), sort_dstpt);
1489 break;
1490 default:
1491 break;
1492 }
1493 }
1494
1495 /* handle window resizes */
1496 if (handle_resize) {
1497 endwin();
1498 initscr();
1499 cbreak();
1500 noecho();
1501 curs_set(0);
1502 timeout(0);
1503 getmaxyx(stdscr, maxy, maxx);
1504 redraw = 1;
1505 handle_resize = 0;
1506 }
1507
1508 /* stop program? */
1509 if (handle_break)
1510 break;
1511
1512 /* print title */
1513 erase();
1514 attron(A_BOLD);
1515 winy = 0;
1516 move(winy,0);
1517 sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION);
1518 for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
1519 printw(" ");
1520 printw("%s", str1);
1521 attroff(A_BOLD);
1522
1523 /* just for fun add a clock */
1524 move(winy, maxx - 8);
1525 t = time(NULL);
1526 strftime(str1, 80, "%T", localtime(&t));
1527 printw("%s\n", str1);
1528
1529 /*
1530 * print the display filters, this is placed in the loop,
1531 * because someday I might add code for changing these
1532 * while the programming is running :-)
1533 */
1534 if (sport >= 0)
1535 sprintf(str1, "%s,%d", getip(ver, &saddr), sport);
1536 else
1537 sprintf(str1, "%s", getip(ver, &saddr));
1538
1539 if (dport >= 0)
1540 sprintf(str2, "%s,%d", getip(ver, &daddr), dport);
1541 else
1542 sprintf(str2, "%s", getip(ver, &daddr));
1543
1544 if (protocol < 0)
1545 strcpy(str3, "any");
1546 else if ((proto = getprotobynumber(protocol)) != NULL)
1547 sprintf(str3, "%s", proto->p_name);
1548 else
1549 sprintf(str3, "%d", protocol);
1550
1551 switch (sorting)
1552 {
1553 case STSORT_PR:
1554 sprintf(str4, "proto");
1555 break;
1556 case STSORT_PKTS:
1557 sprintf(str4, "# pkts");
1558 break;
1559 case STSORT_BYTES:
1560 sprintf(str4, "# bytes");
1561 break;
1562 case STSORT_TTL:
1563 sprintf(str4, "ttl");
1564 break;
1565 case STSORT_SRCIP:
1566 sprintf(str4, "src ip");
1567 break;
1568 case STSORT_SRCPT:
1569 sprintf(str4, "src port");
1570 break;
1571 case STSORT_DSTIP:
1572 sprintf(str4, "dest ip");
1573 break;
1574 case STSORT_DSTPT:
1575 sprintf(str4, "dest port");
1576 break;
1577 default:
1578 sprintf(str4, "unknown");
1579 break;
1580 }
1581
1582 if (reverse)
1583 strcat(str4, " (reverse)");
1584
1585 winy += 2;
1586 move(winy,0);
1587 printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
1588 str1, str2, str3, str4);
1589
1590 /*
1591 * For an IPv4 IP address we need at most 15 characters,
1592 * 4 tuples of 3 digits, separated by 3 dots. Enforce this
1593 * length, so the colums do not change positions based
1594 * on the size of the IP address. This length makes the
1595 * output fit in a 80 column terminal.
1596 * We are lacking a good solution for IPv6 addresses (that
1597 * can be longer that 15 characters), so we do not enforce
1598 * a maximum on the IP field size.
1599 */
1600 if (srclen < 15)
1601 srclen = 15;
1602 if (dstlen < 15)
1603 dstlen = 15;
1604
1605 /* print column description */
1606 winy += 2;
1607 move(winy,0);
1608 attron(A_BOLD);
1609 printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
1610 srclen + 6, "Source IP", dstlen + 6, "Destination IP",
1611 "ST", "PR", "#pkts", "#bytes", "ttl");
1612 attroff(A_BOLD);
1613
1614 /* print all the entries */
1615 tp = tstable;
1616 if (reverse)
1617 tp += tsentry;
1618
1619 if (tsentry > maxy - 6)
1620 tsentry = maxy - 6;
1621 for (i = 0; i <= tsentry; i++) {
1622 /* print src/dest and port */
1623 if ((tp->st_p == IPPROTO_TCP) ||
1624 (tp->st_p == IPPROTO_UDP)) {
1625 sprintf(str1, "%s,%hu",
1626 getip(tp->st_v, &tp->st_src),
1627 ntohs(tp->st_sport));
1628 sprintf(str2, "%s,%hu",
1629 getip(tp->st_v, &tp->st_dst),
1630 ntohs(tp->st_dport));
1631 } else {
1632 sprintf(str1, "%s", getip(tp->st_v,
1633 &tp->st_src));
1634 sprintf(str2, "%s", getip(tp->st_v,
1635 &tp->st_dst));
1636 }
1637 winy++;
1638 move(winy, 0);
1639 printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
1640
1641 /* print state */
1642 sprintf(str1, "%X/%X", tp->st_state[0],
1643 tp->st_state[1]);
1644 printw(" %3s", str1);
1645
1646 /* print protocol */
1647 proto = getprotobynumber(tp->st_p);
1648 if (proto) {
1649 strncpy(str1, proto->p_name, 4);
1650 str1[4] = '\0';
1651 } else {
1652 sprintf(str1, "%d", tp->st_p);
1653 }
1654 /* just print icmp for IPv6-ICMP */
1655 if (tp->st_p == IPPROTO_ICMPV6)
1656 strcpy(str1, "icmp");
1657 printw(" %4s", str1);
1658
1659 /* print #pkt/#bytes */
1660 #ifdef USE_QUAD_T
1661 printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
1662 (unsigned long long) tp->st_bytes);
1663 #else
1664 printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
1665 #endif
1666 printw(" %9s", ttl_to_string(tp->st_age));
1667
1668 if (reverse)
1669 tp--;
1670 else
1671 tp++;
1672 }
1673
1674 /* screen data structure is filled, now update the screen */
1675 if (redraw)
1676 clearok(stdscr,1);
1677
1678 if (refresh() == ERR)
1679 break;
1680 if (redraw) {
1681 clearok(stdscr,0);
1682 redraw = 0;
1683 }
1684
1685 /* wait for key press or a 1 second time out period */
1686 selecttimeout.tv_sec = refreshtime;
1687 selecttimeout.tv_usec = 0;
1688 FD_ZERO(&readfd);
1689 FD_SET(0, &readfd);
1690 select(1, &readfd, NULL, NULL, &selecttimeout);
1691
1692 /* if key pressed, read all waiting keys */
1693 if (FD_ISSET(0, &readfd)) {
1694 c = wgetch(stdscr);
1695 if (c == ERR)
1696 continue;
1697
1698 if (ISALPHA(c) && ISUPPER(c))
1699 c = TOLOWER(c);
1700 if (c == 'l') {
1701 redraw = 1;
1702 } else if (c == 'q') {
1703 break;
1704 } else if (c == 'r') {
1705 reverse = !reverse;
1706 } else if (c == 'b') {
1707 forward = 0;
1708 } else if (c == 'f') {
1709 forward = 1;
1710 } else if (c == 's') {
1711 if (++sorting > STSORT_MAX)
1712 sorting = 0;
1713 }
1714 }
1715 } /* while */
1716
1717 out:
1718 printw("\n");
1719 curs_set(1);
1720 /* nocbreak(); XXX - endwin() should make this redundant */
1721 endwin();
1722
1723 free(tstable);
1724 if (ret != 0)
1725 perror(errstr);
1726 }
1727 #endif
1728
1729
1730 /*
1731 * Show fragment cache information that's held in the kernel.
1732 */
showfrstates(ifsp,ticks)1733 static void showfrstates(ifsp, ticks)
1734 ipfrstat_t *ifsp;
1735 u_long ticks;
1736 {
1737 struct ipfr *ipfrtab[IPFT_SIZE], ifr;
1738 int i;
1739
1740 /*
1741 * print out the numeric statistics
1742 */
1743 PRINTF("IP fragment states:\n%lu\tnew\n%lu\texpired\n%lu\thits\n",
1744 ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
1745 PRINTF("%lu\tretrans\n%lu\ttoo short\n",
1746 ifsp->ifs_retrans0, ifsp->ifs_short);
1747 PRINTF("%lu\tno memory\n%lu\talready exist\n",
1748 ifsp->ifs_nomem, ifsp->ifs_exists);
1749 PRINTF("%lu\tinuse\n", ifsp->ifs_inuse);
1750 PRINTF("\n");
1751
1752 if (live_kernel == 0) {
1753 if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table,
1754 sizeof(ipfrtab)))
1755 return;
1756 }
1757
1758 /*
1759 * Print out the contents (if any) of the fragment cache table.
1760 */
1761 if (live_kernel == 1) {
1762 do {
1763 if (fetchfrag(ipf_fd, IPFGENITER_FRAG, &ifr) != 0)
1764 break;
1765 if (ifr.ipfr_ifp == NULL)
1766 break;
1767 ifr.ipfr_ttl -= ticks;
1768 printfraginfo("", &ifr);
1769 } while (ifr.ipfr_next != NULL);
1770 } else {
1771 for (i = 0; i < IPFT_SIZE; i++)
1772 while (ipfrtab[i] != NULL) {
1773 if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1774 sizeof(ifr)) == -1)
1775 break;
1776 printfraginfo("", &ifr);
1777 ipfrtab[i] = ifr.ipfr_next;
1778 }
1779 }
1780 /*
1781 * Print out the contents (if any) of the NAT fragment cache table.
1782 */
1783
1784 if (live_kernel == 0) {
1785 if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,
1786 sizeof(ipfrtab)))
1787 return;
1788 }
1789
1790 if (live_kernel == 1) {
1791 do {
1792 if (fetchfrag(nat_fd, IPFGENITER_NATFRAG, &ifr) != 0)
1793 break;
1794 if (ifr.ipfr_ifp == NULL)
1795 break;
1796 ifr.ipfr_ttl -= ticks;
1797 printfraginfo("NAT: ", &ifr);
1798 } while (ifr.ipfr_next != NULL);
1799 } else {
1800 for (i = 0; i < IPFT_SIZE; i++)
1801 while (ipfrtab[i] != NULL) {
1802 if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
1803 sizeof(ifr)) == -1)
1804 break;
1805 printfraginfo("NAT: ", &ifr);
1806 ipfrtab[i] = ifr.ipfr_next;
1807 }
1808 }
1809 }
1810
1811
1812 /*
1813 * Show stats on how auth within IPFilter has been used
1814 */
showauthstates(asp)1815 static void showauthstates(asp)
1816 ipf_authstat_t *asp;
1817 {
1818 frauthent_t *frap, fra;
1819 ipfgeniter_t auth;
1820 ipfobj_t obj;
1821
1822 obj.ipfo_rev = IPFILTER_VERSION;
1823 obj.ipfo_type = IPFOBJ_GENITER;
1824 obj.ipfo_size = sizeof(auth);
1825 obj.ipfo_ptr = &auth;
1826
1827 auth.igi_type = IPFGENITER_AUTH;
1828 auth.igi_nitems = 1;
1829 auth.igi_data = &fra;
1830
1831 #ifdef USE_QUAD_T
1832 printf("Authorisation hits: %llu\tmisses %llu\n",
1833 (unsigned long long) asp->fas_hits,
1834 (unsigned long long) asp->fas_miss);
1835 #else
1836 printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
1837 asp->fas_miss);
1838 #endif
1839 printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
1840 asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
1841 asp->fas_sendok);
1842 printf("queok %ld\nquefail %ld\nexpire %ld\n",
1843 asp->fas_queok, asp->fas_quefail, asp->fas_expire);
1844
1845 frap = asp->fas_faelist;
1846 while (frap) {
1847 if (live_kernel == 1) {
1848 if (ioctl(auth_fd, SIOCGENITER, &obj))
1849 break;
1850 } else {
1851 if (kmemcpy((char *)&fra, (u_long)frap,
1852 sizeof(fra)) == -1)
1853 break;
1854 }
1855 printf("age %ld\t", fra.fae_age);
1856 printfr(&fra.fae_fr, ioctl);
1857 frap = fra.fae_next;
1858 }
1859 }
1860
1861
1862 /*
1863 * Display groups used for each of filter rules, accounting rules and
1864 * authentication, separately.
1865 */
showgroups(fiop)1866 static void showgroups(fiop)
1867 struct friostat *fiop;
1868 {
1869 static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
1870 static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH };
1871 frgroup_t *fp, grp;
1872 int on, off, i;
1873
1874 on = fiop->f_active;
1875 off = 1 - on;
1876
1877 for (i = 0; i < 3; i++) {
1878 printf("%s groups (active):\n", gnames[i]);
1879 for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL;
1880 fp = grp.fg_next)
1881 if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1882 break;
1883 else
1884 printf("%s\n", grp.fg_name);
1885 printf("%s groups (inactive):\n", gnames[i]);
1886 for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL;
1887 fp = grp.fg_next)
1888 if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
1889 break;
1890 else
1891 printf("%s\n", grp.fg_name);
1892 }
1893 }
1894
1895
parse_ipportstr(argument,ip,port)1896 static void parse_ipportstr(argument, ip, port)
1897 const char *argument;
1898 i6addr_t *ip;
1899 int *port;
1900 {
1901 char *s, *comma;
1902 int ok = 0;
1903
1904 /* make working copy of argument, Theoretically you must be able
1905 * to write to optarg, but that seems very ugly to me....
1906 */
1907 s = strdup(argument);
1908 if (s == NULL)
1909 return;
1910
1911 /* get port */
1912 if ((comma = strchr(s, ',')) != NULL) {
1913 if (!strcasecmp(comma + 1, "any")) {
1914 *port = -1;
1915 } else if (!sscanf(comma + 1, "%d", port) ||
1916 (*port < 0) || (*port > 65535)) {
1917 fprintf(stderr, "Invalid port specification in %s\n",
1918 argument);
1919 free(s);
1920 exit(-2);
1921 }
1922 *comma = '\0';
1923 }
1924
1925
1926 /* get ip address */
1927 if (!strcasecmp(s, "any")) {
1928 ip->in4.s_addr = INADDR_ANY;
1929 ok = 1;
1930 #ifdef USE_INET6
1931 ip->in6 = in6addr_any;
1932 } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) {
1933 ok = 1;
1934 #endif
1935 } else if (inet_aton(s, &ip->in4))
1936 ok = 1;
1937
1938 if (ok == 0) {
1939 fprintf(stderr, "Invalid IP address: %s\n", s);
1940 free(s);
1941 exit(-2);
1942 }
1943
1944 /* free allocated memory */
1945 free(s);
1946 }
1947
1948
1949 #ifdef STATETOP
sig_resize(s)1950 static void sig_resize(s)
1951 int s;
1952 {
1953 handle_resize = 1;
1954 }
1955
sig_break(s)1956 static void sig_break(s)
1957 int s;
1958 {
1959 handle_break = 1;
1960 }
1961
getip(v,addr)1962 static char *getip(v, addr)
1963 int v;
1964 i6addr_t *addr;
1965 {
1966 #ifdef USE_INET6
1967 static char hostbuf[MAXHOSTNAMELEN+1];
1968 #endif
1969
1970 if (v == 4)
1971 return inet_ntoa(addr->in4);
1972
1973 #ifdef USE_INET6
1974 (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1);
1975 hostbuf[MAXHOSTNAMELEN] = '\0';
1976 return hostbuf;
1977 #else
1978 return "IPv6";
1979 #endif
1980 }
1981
1982
ttl_to_string(ttl)1983 static char *ttl_to_string(ttl)
1984 long int ttl;
1985 {
1986 static char ttlbuf[STSTRSIZE];
1987 int hours, minutes, seconds;
1988
1989 /* ttl is in half seconds */
1990 ttl /= 2;
1991
1992 hours = ttl / 3600;
1993 ttl = ttl % 3600;
1994 minutes = ttl / 60;
1995 seconds = ttl % 60;
1996
1997 if (hours > 0)
1998 sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds);
1999 else
2000 sprintf(ttlbuf, "%2d:%02d", minutes, seconds);
2001 return ttlbuf;
2002 }
2003
2004
sort_pkts(a,b)2005 static int sort_pkts(a, b)
2006 const void *a;
2007 const void *b;
2008 {
2009
2010 register const statetop_t *ap = a;
2011 register const statetop_t *bp = b;
2012
2013 if (ap->st_pkts == bp->st_pkts)
2014 return 0;
2015 else if (ap->st_pkts < bp->st_pkts)
2016 return 1;
2017 return -1;
2018 }
2019
2020
sort_bytes(a,b)2021 static int sort_bytes(a, b)
2022 const void *a;
2023 const void *b;
2024 {
2025 register const statetop_t *ap = a;
2026 register const statetop_t *bp = b;
2027
2028 if (ap->st_bytes == bp->st_bytes)
2029 return 0;
2030 else if (ap->st_bytes < bp->st_bytes)
2031 return 1;
2032 return -1;
2033 }
2034
2035
sort_p(a,b)2036 static int sort_p(a, b)
2037 const void *a;
2038 const void *b;
2039 {
2040 register const statetop_t *ap = a;
2041 register const statetop_t *bp = b;
2042
2043 if (ap->st_p == bp->st_p)
2044 return 0;
2045 else if (ap->st_p < bp->st_p)
2046 return 1;
2047 return -1;
2048 }
2049
2050
sort_ttl(a,b)2051 static int sort_ttl(a, b)
2052 const void *a;
2053 const void *b;
2054 {
2055 register const statetop_t *ap = a;
2056 register const statetop_t *bp = b;
2057
2058 if (ap->st_age == bp->st_age)
2059 return 0;
2060 else if (ap->st_age < bp->st_age)
2061 return 1;
2062 return -1;
2063 }
2064
sort_srcip(a,b)2065 static int sort_srcip(a, b)
2066 const void *a;
2067 const void *b;
2068 {
2069 register const statetop_t *ap = a;
2070 register const statetop_t *bp = b;
2071
2072 #ifdef USE_INET6
2073 if (use_inet6) {
2074 if (IP6_EQ(&ap->st_src, &bp->st_src))
2075 return 0;
2076 else if (IP6_GT(&ap->st_src, &bp->st_src))
2077 return 1;
2078 } else
2079 #endif
2080 {
2081 if (ntohl(ap->st_src.in4.s_addr) ==
2082 ntohl(bp->st_src.in4.s_addr))
2083 return 0;
2084 else if (ntohl(ap->st_src.in4.s_addr) >
2085 ntohl(bp->st_src.in4.s_addr))
2086 return 1;
2087 }
2088 return -1;
2089 }
2090
sort_srcpt(a,b)2091 static int sort_srcpt(a, b)
2092 const void *a;
2093 const void *b;
2094 {
2095 register const statetop_t *ap = a;
2096 register const statetop_t *bp = b;
2097
2098 if (htons(ap->st_sport) == htons(bp->st_sport))
2099 return 0;
2100 else if (htons(ap->st_sport) > htons(bp->st_sport))
2101 return 1;
2102 return -1;
2103 }
2104
sort_dstip(a,b)2105 static int sort_dstip(a, b)
2106 const void *a;
2107 const void *b;
2108 {
2109 register const statetop_t *ap = a;
2110 register const statetop_t *bp = b;
2111
2112 #ifdef USE_INET6
2113 if (use_inet6) {
2114 if (IP6_EQ(&ap->st_dst, &bp->st_dst))
2115 return 0;
2116 else if (IP6_GT(&ap->st_dst, &bp->st_dst))
2117 return 1;
2118 } else
2119 #endif
2120 {
2121 if (ntohl(ap->st_dst.in4.s_addr) ==
2122 ntohl(bp->st_dst.in4.s_addr))
2123 return 0;
2124 else if (ntohl(ap->st_dst.in4.s_addr) >
2125 ntohl(bp->st_dst.in4.s_addr))
2126 return 1;
2127 }
2128 return -1;
2129 }
2130
sort_dstpt(a,b)2131 static int sort_dstpt(a, b)
2132 const void *a;
2133 const void *b;
2134 {
2135 register const statetop_t *ap = a;
2136 register const statetop_t *bp = b;
2137
2138 if (htons(ap->st_dport) == htons(bp->st_dport))
2139 return 0;
2140 else if (htons(ap->st_dport) > htons(bp->st_dport))
2141 return 1;
2142 return -1;
2143 }
2144
2145 #endif
2146
2147
fetchstate(src,dst)2148 ipstate_t *fetchstate(src, dst)
2149 ipstate_t *src, *dst;
2150 {
2151
2152 if (live_kernel == 1) {
2153 ipfgeniter_t state;
2154 ipfobj_t obj;
2155
2156 obj.ipfo_rev = IPFILTER_VERSION;
2157 obj.ipfo_type = IPFOBJ_GENITER;
2158 obj.ipfo_size = sizeof(state);
2159 obj.ipfo_ptr = &state;
2160
2161 state.igi_type = IPFGENITER_STATE;
2162 state.igi_nitems = 1;
2163 state.igi_data = dst;
2164
2165 if (ioctl(state_fd, SIOCGENITER, &obj) != 0)
2166 return NULL;
2167 if (dst->is_next == NULL) {
2168 int n = IPFGENITER_STATE;
2169 (void) ioctl(ipf_fd,SIOCIPFDELTOK, &n);
2170 }
2171 } else {
2172 if (kmemcpy((char *)dst, (u_long)src, sizeof(*dst)))
2173 return NULL;
2174 }
2175 return dst;
2176 }
2177
2178
fetchfrag(fd,type,frp)2179 static int fetchfrag(fd, type, frp)
2180 int fd, type;
2181 ipfr_t *frp;
2182 {
2183 ipfgeniter_t frag;
2184 ipfobj_t obj;
2185
2186 obj.ipfo_rev = IPFILTER_VERSION;
2187 obj.ipfo_type = IPFOBJ_GENITER;
2188 obj.ipfo_size = sizeof(frag);
2189 obj.ipfo_ptr = &frag;
2190
2191 frag.igi_type = type;
2192 frag.igi_nitems = 1;
2193 frag.igi_data = frp;
2194
2195 if (ioctl(fd, SIOCGENITER, &obj))
2196 return EFAULT;
2197 return 0;
2198 }
2199
2200
state_matcharray(stp,array)2201 static int state_matcharray(stp, array)
2202 ipstate_t *stp;
2203 int *array;
2204 {
2205 int i, n, *x, rv, p;
2206 ipfexp_t *e;
2207
2208 rv = 0;
2209
2210 for (n = array[0], x = array + 1; n > 0; x += e->ipfe_size) {
2211 e = (ipfexp_t *)x;
2212 if (e->ipfe_cmd == IPF_EXP_END)
2213 break;
2214 n -= e->ipfe_size;
2215
2216 rv = 0;
2217 /*
2218 * The upper 16 bits currently store the protocol value.
2219 * This is currently used with TCP and UDP port compares and
2220 * allows "tcp.port = 80" without requiring an explicit
2221 " "ip.pr = tcp" first.
2222 */
2223 p = e->ipfe_cmd >> 16;
2224 if ((p != 0) && (p != stp->is_p))
2225 break;
2226
2227 switch (e->ipfe_cmd)
2228 {
2229 case IPF_EXP_IP_PR :
2230 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2231 rv |= (stp->is_p == e->ipfe_arg0[i]);
2232 }
2233 break;
2234
2235 case IPF_EXP_IP_SRCADDR :
2236 if (stp->is_v != 4)
2237 break;
2238 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2239 rv |= ((stp->is_saddr &
2240 e->ipfe_arg0[i * 2 + 1]) ==
2241 e->ipfe_arg0[i * 2]);
2242 }
2243 break;
2244
2245 case IPF_EXP_IP_DSTADDR :
2246 if (stp->is_v != 4)
2247 break;
2248 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2249 rv |= ((stp->is_daddr &
2250 e->ipfe_arg0[i * 2 + 1]) ==
2251 e->ipfe_arg0[i * 2]);
2252 }
2253 break;
2254
2255 case IPF_EXP_IP_ADDR :
2256 if (stp->is_v != 4)
2257 break;
2258 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2259 rv |= ((stp->is_saddr &
2260 e->ipfe_arg0[i * 2 + 1]) ==
2261 e->ipfe_arg0[i * 2]) ||
2262 ((stp->is_daddr &
2263 e->ipfe_arg0[i * 2 + 1]) ==
2264 e->ipfe_arg0[i * 2]);
2265 }
2266 break;
2267
2268 #ifdef USE_INET6
2269 case IPF_EXP_IP6_SRCADDR :
2270 if (stp->is_v != 6)
2271 break;
2272 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2273 rv |= IP6_MASKEQ(&stp->is_src,
2274 &e->ipfe_arg0[i * 8 + 4],
2275 &e->ipfe_arg0[i * 8]);
2276 }
2277 break;
2278
2279 case IPF_EXP_IP6_DSTADDR :
2280 if (stp->is_v != 6)
2281 break;
2282 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2283 rv |= IP6_MASKEQ(&stp->is_dst,
2284 &e->ipfe_arg0[i * 8 + 4],
2285 &e->ipfe_arg0[i * 8]);
2286 }
2287 break;
2288
2289 case IPF_EXP_IP6_ADDR :
2290 if (stp->is_v != 6)
2291 break;
2292 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2293 rv |= IP6_MASKEQ(&stp->is_src,
2294 &e->ipfe_arg0[i * 8 + 4],
2295 &e->ipfe_arg0[i * 8]) ||
2296 IP6_MASKEQ(&stp->is_dst,
2297 &e->ipfe_arg0[i * 8 + 4],
2298 &e->ipfe_arg0[i * 8]);
2299 }
2300 break;
2301 #endif
2302
2303 case IPF_EXP_UDP_PORT :
2304 case IPF_EXP_TCP_PORT :
2305 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2306 rv |= (stp->is_sport == e->ipfe_arg0[i]) ||
2307 (stp->is_dport == e->ipfe_arg0[i]);
2308 }
2309 break;
2310
2311 case IPF_EXP_UDP_SPORT :
2312 case IPF_EXP_TCP_SPORT :
2313 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2314 rv |= (stp->is_sport == e->ipfe_arg0[i]);
2315 }
2316 break;
2317
2318 case IPF_EXP_UDP_DPORT :
2319 case IPF_EXP_TCP_DPORT :
2320 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2321 rv |= (stp->is_dport == e->ipfe_arg0[i]);
2322 }
2323 break;
2324
2325 case IPF_EXP_IDLE_GT :
2326 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2327 rv |= (stp->is_die < e->ipfe_arg0[i]);
2328 }
2329 break;
2330
2331 case IPF_EXP_TCP_STATE :
2332 for (i = 0; !rv && i < e->ipfe_narg; i++) {
2333 rv |= (stp->is_state[0] == e->ipfe_arg0[i]) ||
2334 (stp->is_state[1] == e->ipfe_arg0[i]);
2335 }
2336 break;
2337 }
2338 rv ^= e->ipfe_not;
2339
2340 if (rv == 0)
2341 break;
2342 }
2343
2344 return rv;
2345 }
2346
2347
showtqtable_live(fd)2348 static void showtqtable_live(fd)
2349 int fd;
2350 {
2351 ipftq_t table[IPF_TCP_NSTATES];
2352 ipfobj_t obj;
2353
2354 bzero((char *)&obj, sizeof(obj));
2355 obj.ipfo_rev = IPFILTER_VERSION;
2356 obj.ipfo_size = sizeof(table);
2357 obj.ipfo_ptr = (void *)table;
2358 obj.ipfo_type = IPFOBJ_STATETQTAB;
2359
2360 if (ioctl(fd, SIOCGTQTAB, &obj) == 0) {
2361 printtqtable(table);
2362 }
2363 }
2364