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