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