1 /* 2 * Copyright (C) 1993-2001, 2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 7 * Use is subject to license terms. 8 */ 9 10 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #ifdef __FreeBSD__ 13 # ifndef __FreeBSD_cc_version 14 # include <osreldate.h> 15 # else 16 # if __FreeBSD_cc_version < 430000 17 # include <osreldate.h> 18 # endif 19 # endif 20 #endif 21 #include <sys/ioctl.h> 22 #include <fcntl.h> 23 #ifdef linux 24 # include <linux/a.out.h> 25 #else 26 # include <nlist.h> 27 #endif 28 #include <ctype.h> 29 #if defined(sun) && (defined(__svr4__) || defined(__SVR4)) 30 # include <stddef.h> 31 #endif 32 #include "ipf.h" 33 #include "netinet/ipl.h" 34 #if defined(STATETOP) 35 # if defined(_BSDI_VERSION) 36 # undef STATETOP 37 # endif 38 # if defined(__FreeBSD__) && \ 39 (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000)) 40 # undef STATETOP 41 # endif 42 # if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105000000) 43 # undef STATETOP 44 # endif 45 # if defined(sun) 46 # if defined(__svr4__) || defined(__SVR4) 47 # include <sys/select.h> 48 # else 49 # undef STATETOP /* NOT supported on SunOS4 */ 50 # endif 51 # endif 52 #endif 53 #if defined(STATETOP) && !defined(linux) 54 # include <netinet/ip_var.h> 55 # include <netinet/tcp_fsm.h> 56 #endif 57 #ifdef STATETOP 58 # include <ctype.h> 59 # include <signal.h> 60 # if SOLARIS || defined(__NetBSD__) || defined(_BSDI_VERSION) || \ 61 defined(__sgi) 62 # ifdef ERR 63 # undef ERR 64 # endif 65 # undef ISASCII 66 # undef ISPRINT 67 # include <curses.h> 68 # else /* SOLARIS */ 69 # include <ncurses.h> 70 # endif /* SOLARIS */ 71 #endif /* STATETOP */ 72 #include "kmem.h" 73 #if defined(__NetBSD__) || (__OpenBSD__) 74 # include <paths.h> 75 #endif 76 77 #if !defined(lint) 78 static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed"; 79 static const char rcsid[] = "@(#)$Id: ipfstat.c,v 1.44.2.12 2005/06/12 07:18:46 darrenr Exp $"; 80 #endif 81 82 #ifdef __hpux 83 # define nlist nlist64 84 #endif 85 86 extern char *optarg; 87 extern int optind; 88 extern int opterr; 89 90 #define PRINTF (void)printf 91 #define FPRINTF (void)fprintf 92 static char *filters[4] = { "ipfilter(in)", "ipfilter(out)", 93 "ipacct(in)", "ipacct(out)" }; 94 static int state_logging = -1; 95 96 int opts = 0; 97 int use_inet6 = 0; 98 int live_kernel = 1; 99 int state_fd = -1; 100 int ipf_fd = -1; 101 102 #ifdef STATETOP 103 #define STSTRSIZE 80 104 #define STGROWSIZE 16 105 #define HOSTNMLEN 40 106 107 #define STSORT_PR 0 108 #define STSORT_PKTS 1 109 #define STSORT_BYTES 2 110 #define STSORT_TTL 3 111 #define STSORT_SRCIP 4 112 #define STSORT_SRCPT 5 113 #define STSORT_DSTIP 6 114 #define STSORT_DSTPT 7 115 #define STSORT_MAX STSORT_DSTPT 116 #define STSORT_DEFAULT STSORT_BYTES 117 118 119 typedef struct statetop { 120 i6addr_t st_src; 121 i6addr_t st_dst; 122 u_short st_sport; 123 u_short st_dport; 124 u_char st_p; 125 u_char st_v; 126 u_char st_state[2]; 127 U_QUAD_T st_pkts; 128 U_QUAD_T st_bytes; 129 u_long st_age; 130 } statetop_t; 131 #endif 132 133 int main __P((int, char *[])); 134 135 static void showstats __P((friostat_t *, u_32_t)); 136 static void showfrstates __P((ipfrstat_t *)); 137 static void showlist __P((friostat_t *)); 138 static void showipstates __P((ips_stat_t *)); 139 static void showauthstates __P((fr_authstat_t *)); 140 static void showgroups __P((friostat_t *)); 141 static void usage __P((char *)); 142 static void printlivelist __P((int, int, frentry_t *, char *, char *)); 143 static void printdeadlist __P((int, int, frentry_t *, char *, char *)); 144 static void printlist __P((frentry_t *, char *)); 145 static void parse_ipportstr __P((const char *, i6addr_t *, int *)); 146 static void ipfstate_live __P((char *, friostat_t **, ips_stat_t **, 147 ipfrstat_t **, fr_authstat_t **, u_32_t *)); 148 static void ipfstate_dead __P((char *, friostat_t **, ips_stat_t **, 149 ipfrstat_t **, fr_authstat_t **, u_32_t *)); 150 #ifdef STATETOP 151 static void topipstates __P((i6addr_t, i6addr_t, int, int, int, 152 int, int, int)); 153 static void sig_break __P((int)); 154 static void sig_resize __P((int)); 155 static char *getip __P((int, i6addr_t *)); 156 static char *ttl_to_string __P((long)); 157 static int sort_p __P((const void *, const void *)); 158 static int sort_pkts __P((const void *, const void *)); 159 static int sort_bytes __P((const void *, const void *)); 160 static int sort_ttl __P((const void *, const void *)); 161 static int sort_srcip __P((const void *, const void *)); 162 static int sort_srcpt __P((const void *, const void *)); 163 static int sort_dstip __P((const void *, const void *)); 164 static int sort_dstpt __P((const void *, const void *)); 165 #endif 166 167 168 static void usage(name) 169 char *name; 170 { 171 #ifdef USE_INET6 172 fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name); 173 #else 174 fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name); 175 #endif 176 fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name); 177 #ifdef USE_INET6 178 fprintf(stderr, " %s -t [-6C] ", name); 179 #else 180 fprintf(stderr, " %s -t [-C] ", name); 181 #endif 182 fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n"); 183 exit(1); 184 } 185 186 187 int main(argc,argv) 188 int argc; 189 char *argv[]; 190 { 191 fr_authstat_t frauthst; 192 fr_authstat_t *frauthstp = &frauthst; 193 friostat_t fio; 194 friostat_t *fiop = &fio; 195 ips_stat_t ipsst; 196 ips_stat_t *ipsstp = &ipsst; 197 ipfrstat_t ifrst; 198 ipfrstat_t *ifrstp = &ifrst; 199 char *device = IPL_NAME, *memf = NULL; 200 char *options, *kern = NULL; 201 int c, myoptind; 202 203 int protocol = -1; /* -1 = wild card for any protocol */ 204 int refreshtime = 1; /* default update time */ 205 int sport = -1; /* -1 = wild card for any source port */ 206 int dport = -1; /* -1 = wild card for any dest port */ 207 int topclosed = 0; /* do not show closed tcp sessions */ 208 i6addr_t saddr, daddr; 209 u_32_t frf; 210 211 #ifdef USE_INET6 212 options = "6aACdfghIilnostvD:M:N:P:RS:T:"; 213 #else 214 options = "aACdfghIilnostvD:M:N:P:RS:T:"; 215 #endif 216 217 saddr.in4.s_addr = INADDR_ANY; /* default any v4 source addr */ 218 daddr.in4.s_addr = INADDR_ANY; /* default any v4 dest addr */ 219 #ifdef USE_INET6 220 saddr.in6 = in6addr_any; /* default any v6 source addr */ 221 daddr.in6 = in6addr_any; /* default any v6 dest addr */ 222 #endif 223 224 /* Don't warn about invalid flags when we run getopt for the 1st time */ 225 opterr = 0; 226 227 /* 228 * Parse these two arguments now lest there be any buffer overflows 229 * in the parsing of the rest. 230 */ 231 myoptind = optind; 232 while ((c = getopt(argc, argv, options)) != -1) { 233 switch (c) 234 { 235 case 'M' : 236 memf = optarg; 237 live_kernel = 0; 238 break; 239 case 'N' : 240 kern = optarg; 241 live_kernel = 0; 242 break; 243 } 244 } 245 optind = myoptind; 246 247 if (live_kernel == 1) { 248 if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) { 249 perror("open(IPSTATE_NAME)"); 250 exit(-1); 251 } 252 if ((ipf_fd = open(device, O_RDONLY)) == -1) { 253 fprintf(stderr, "open(%s)", device); 254 perror(""); 255 exit(-1); 256 } 257 } 258 259 if (kern != NULL || memf != NULL) { 260 (void)setgid(getgid()); 261 (void)setreuid(getuid(), getuid()); 262 if (openkmem(kern, memf) == -1) 263 exit(-1); 264 } 265 266 if (live_kernel == 1) 267 (void) checkrev(device); 268 (void)setgid(getgid()); 269 (void)setreuid(getuid(), getuid()); 270 271 opterr = 1; 272 273 while ((c = getopt(argc, argv, options)) != -1) 274 { 275 switch (c) 276 { 277 #ifdef USE_INET6 278 case '6' : 279 use_inet6 = 1; 280 break; 281 #endif 282 case 'a' : 283 opts |= OPT_ACCNT|OPT_SHOWLIST; 284 break; 285 case 'A' : 286 opts |= OPT_AUTHSTATS; 287 break; 288 case 'C' : 289 topclosed = 1; 290 break; 291 case 'd' : 292 opts |= OPT_DEBUG; 293 break; 294 case 'D' : 295 parse_ipportstr(optarg, &daddr, &dport); 296 break; 297 case 'f' : 298 opts |= OPT_FRSTATES; 299 break; 300 case 'g' : 301 opts |= OPT_GROUPS; 302 break; 303 case 'h' : 304 opts |= OPT_HITS; 305 break; 306 case 'i' : 307 opts |= OPT_INQUE|OPT_SHOWLIST; 308 break; 309 case 'I' : 310 opts |= OPT_INACTIVE; 311 break; 312 case 'l' : 313 opts |= OPT_SHOWLIST; 314 break; 315 case 'M' : 316 break; 317 case 'N' : 318 break; 319 case 'n' : 320 opts |= OPT_SHOWLINENO; 321 break; 322 case 'o' : 323 opts |= OPT_OUTQUE|OPT_SHOWLIST; 324 break; 325 case 'P' : 326 protocol = getproto(optarg); 327 if (protocol == -1) { 328 fprintf(stderr, "%s: Invalid protocol: %s\n", 329 argv[0], optarg); 330 exit(-2); 331 } 332 break; 333 case 'R' : 334 opts |= OPT_NORESOLVE; 335 break; 336 case 's' : 337 opts |= OPT_IPSTATES; 338 break; 339 case 'S' : 340 parse_ipportstr(optarg, &saddr, &sport); 341 break; 342 case 't' : 343 #ifdef STATETOP 344 opts |= OPT_STATETOP; 345 break; 346 #else 347 fprintf(stderr, 348 "%s: state top facility not compiled in\n", 349 argv[0]); 350 exit(-2); 351 #endif 352 case 'T' : 353 if (!sscanf(optarg, "%d", &refreshtime) || 354 (refreshtime <= 0)) { 355 fprintf(stderr, 356 "%s: Invalid refreshtime < 1 : %s\n", 357 argv[0], optarg); 358 exit(-2); 359 } 360 break; 361 case 'v' : 362 opts |= OPT_VERBOSE; 363 opts |= OPT_UNDEF; 364 break; 365 default : 366 usage(argv[0]); 367 break; 368 } 369 } 370 371 if (live_kernel == 1) { 372 bzero((char *)&fio, sizeof(fio)); 373 bzero((char *)&ipsst, sizeof(ipsst)); 374 bzero((char *)&ifrst, sizeof(ifrst)); 375 376 ipfstate_live(device, &fiop, &ipsstp, &ifrstp, 377 &frauthstp, &frf); 378 } else 379 ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); 380 381 if (opts & OPT_IPSTATES) { 382 showipstates(ipsstp); 383 } else if (opts & OPT_SHOWLIST) { 384 showlist(fiop); 385 if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){ 386 opts &= ~OPT_OUTQUE; 387 showlist(fiop); 388 } 389 } else if (opts & OPT_FRSTATES) 390 showfrstates(ifrstp); 391 #ifdef STATETOP 392 else if (opts & OPT_STATETOP) 393 topipstates(saddr, daddr, sport, dport, protocol, 394 use_inet6 ? 6 : 4, refreshtime, topclosed); 395 #endif 396 else if (opts & OPT_AUTHSTATS) 397 showauthstates(frauthstp); 398 else if (opts & OPT_GROUPS) 399 showgroups(fiop); 400 else 401 showstats(fiop, frf); 402 403 return 0; 404 } 405 406 407 /* 408 * Fill in the stats structures from the live kernel, using a combination 409 * of ioctl's and copying directly from kernel memory. 410 */ 411 static void ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) 412 char *device; 413 friostat_t **fiopp; 414 ips_stat_t **ipsstpp; 415 ipfrstat_t **ifrstpp; 416 fr_authstat_t **frauthstpp; 417 u_32_t *frfp; 418 { 419 ipfobj_t ipfo; 420 421 if (checkrev(device) == -1) { 422 fprintf(stderr, "User/kernel version check failed\n"); 423 exit(1); 424 } 425 426 if ((opts & OPT_AUTHSTATS) == 0) { 427 bzero((caddr_t)&ipfo, sizeof(ipfo)); 428 ipfo.ipfo_rev = IPFILTER_VERSION; 429 ipfo.ipfo_size = sizeof(friostat_t); 430 ipfo.ipfo_ptr = (void *)*fiopp; 431 ipfo.ipfo_type = IPFOBJ_IPFSTAT; 432 433 if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) { 434 perror("ioctl(ipf:SIOCGETFS)"); 435 exit(-1); 436 } 437 438 if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1) 439 perror("ioctl(SIOCGETFF)"); 440 } 441 442 if ((opts & OPT_IPSTATES) != 0) { 443 444 bzero((caddr_t)&ipfo, sizeof(ipfo)); 445 ipfo.ipfo_rev = IPFILTER_VERSION; 446 ipfo.ipfo_size = sizeof(ips_stat_t); 447 ipfo.ipfo_ptr = (void *)*ipsstpp; 448 ipfo.ipfo_type = IPFOBJ_STATESTAT; 449 450 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { 451 perror("ioctl(state:SIOCGETFS)"); 452 exit(-1); 453 } 454 if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) { 455 perror("ioctl(state:SIOCGETLG)"); 456 exit(-1); 457 } 458 } 459 460 if ((opts & OPT_FRSTATES) != 0) { 461 bzero((caddr_t)&ipfo, sizeof(ipfo)); 462 ipfo.ipfo_rev = IPFILTER_VERSION; 463 ipfo.ipfo_size = sizeof(ipfrstat_t); 464 ipfo.ipfo_ptr = (void *)*ifrstpp; 465 ipfo.ipfo_type = IPFOBJ_FRAGSTAT; 466 467 if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) { 468 perror("ioctl(SIOCGFRST)"); 469 exit(-1); 470 } 471 } 472 473 if (opts & OPT_VERBOSE) 474 PRINTF("opts %#x name %s\n", opts, device); 475 476 if ((opts & OPT_AUTHSTATS) != 0) { 477 if (ipf_fd >= 0) { 478 close(ipf_fd); 479 ipf_fd = -1; 480 } 481 device = IPAUTH_NAME; 482 if ((ipf_fd = open(device, O_RDONLY)) == -1) { 483 perror("open"); 484 exit(-1); 485 } 486 487 bzero((caddr_t)&ipfo, sizeof(ipfo)); 488 ipfo.ipfo_rev = IPFILTER_VERSION; 489 ipfo.ipfo_size = sizeof(fr_authstat_t); 490 ipfo.ipfo_ptr = (void *)*frauthstpp; 491 ipfo.ipfo_type = IPFOBJ_AUTHSTAT; 492 493 if (ioctl(ipf_fd, SIOCATHST, &ipfo) == -1) { 494 perror("ioctl(SIOCATHST)"); 495 exit(-1); 496 } 497 } 498 } 499 500 501 /* 502 * Build up the stats structures from data held in the "core" memory. 503 * This is mainly useful when looking at data in crash dumps and ioctl's 504 * just won't work any more. 505 */ 506 static void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) 507 char *kernel; 508 friostat_t **fiopp; 509 ips_stat_t **ipsstpp; 510 ipfrstat_t **ifrstpp; 511 fr_authstat_t **frauthstpp; 512 u_32_t *frfp; 513 { 514 static fr_authstat_t frauthst, *frauthstp; 515 static ips_stat_t ipsst, *ipsstp; 516 static ipfrstat_t ifrst, *ifrstp; 517 static friostat_t fio, *fiop; 518 int temp; 519 520 void *rules[2][2]; 521 struct nlist deadlist[43] = { 522 { "fr_authstats" }, /* 0 */ 523 { "fae_list" }, 524 { "ipauth" }, 525 { "fr_authlist" }, 526 { "fr_authstart" }, 527 { "fr_authend" }, /* 5 */ 528 { "fr_authnext" }, 529 { "fr_auth" }, 530 { "fr_authused" }, 531 { "fr_authsize" }, 532 { "fr_defaultauthage" }, /* 10 */ 533 { "fr_authpkts" }, 534 { "fr_auth_lock" }, 535 { "frstats" }, 536 { "ips_stats" }, 537 { "ips_num" }, /* 15 */ 538 { "ips_wild" }, 539 { "ips_list" }, 540 { "ips_table" }, 541 { "fr_statemax" }, 542 { "fr_statesize" }, /* 20 */ 543 { "fr_state_doflush" }, 544 { "fr_state_lock" }, 545 { "ipfr_heads" }, 546 { "ipfr_nattab" }, 547 { "ipfr_stats" }, /* 25 */ 548 { "ipfr_inuse" }, 549 { "fr_ipfrttl" }, 550 { "fr_frag_lock" }, 551 { "ipfr_timer_id" }, 552 { "fr_nat_lock" }, /* 30 */ 553 { "ipfilter" }, 554 { "ipfilter6" }, 555 { "ipacct" }, 556 { "ipacct6" }, 557 { "ipl_frouteok" }, /* 35 */ 558 { "fr_running" }, 559 { "ipfgroups" }, 560 { "fr_active" }, 561 { "fr_pass" }, 562 { "fr_flags" }, /* 40 */ 563 { "ipstate_logging" }, 564 { NULL } 565 }; 566 567 568 frauthstp = &frauthst; 569 ipsstp = &ipsst; 570 ifrstp = &ifrst; 571 fiop = &fio; 572 573 *frfp = 0; 574 *fiopp = fiop; 575 *ipsstpp = ipsstp; 576 *ifrstpp = ifrstp; 577 *frauthstpp = frauthstp; 578 579 bzero((char *)fiop, sizeof(*fiop)); 580 bzero((char *)ipsstp, sizeof(*ipsstp)); 581 bzero((char *)ifrstp, sizeof(*ifrstp)); 582 bzero((char *)frauthstp, sizeof(*frauthstp)); 583 584 if (nlist(kernel, deadlist) == -1) { 585 fprintf(stderr, "nlist error\n"); 586 return; 587 } 588 589 /* 590 * This is for SIOCGETFF. 591 */ 592 kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp)); 593 594 /* 595 * f_locks is a combination of the lock variable from each part of 596 * ipfilter (state, auth, nat, fragments). 597 */ 598 kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop)); 599 kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value, 600 sizeof(fiop->f_locks[0])); 601 kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value, 602 sizeof(fiop->f_locks[1])); 603 kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value, 604 sizeof(fiop->f_locks[2])); 605 kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value, 606 sizeof(fiop->f_locks[3])); 607 608 /* 609 * Get pointers to each list of rules (active, inactive, in, out) 610 */ 611 kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules)); 612 fiop->f_fin[0] = rules[0][0]; 613 fiop->f_fin[1] = rules[0][1]; 614 fiop->f_fout[0] = rules[1][0]; 615 fiop->f_fout[1] = rules[1][1]; 616 617 /* 618 * Same for IPv6, except make them null if support for it is not 619 * being compiled in. 620 */ 621 #ifdef USE_INET6 622 kmemcpy((char *)&rules, (u_long)deadlist[32].n_value, sizeof(rules)); 623 fiop->f_fin6[0] = rules[0][0]; 624 fiop->f_fin6[1] = rules[0][1]; 625 fiop->f_fout6[0] = rules[1][0]; 626 fiop->f_fout6[1] = rules[1][1]; 627 #else 628 fiop->f_fin6[0] = NULL; 629 fiop->f_fin6[1] = NULL; 630 fiop->f_fout6[0] = NULL; 631 fiop->f_fout6[1] = NULL; 632 #endif 633 634 /* 635 * Now get accounting rules pointers. 636 */ 637 kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules)); 638 fiop->f_acctin[0] = rules[0][0]; 639 fiop->f_acctin[1] = rules[0][1]; 640 fiop->f_acctout[0] = rules[1][0]; 641 fiop->f_acctout[1] = rules[1][1]; 642 643 #ifdef USE_INET6 644 kmemcpy((char *)&rules, (u_long)deadlist[34].n_value, sizeof(rules)); 645 fiop->f_acctin6[0] = rules[0][0]; 646 fiop->f_acctin6[1] = rules[0][1]; 647 fiop->f_acctout6[0] = rules[1][0]; 648 fiop->f_acctout6[1] = rules[1][1]; 649 #else 650 fiop->f_acctin6[0] = NULL; 651 fiop->f_acctin6[1] = NULL; 652 fiop->f_acctout6[0] = NULL; 653 fiop->f_acctout6[1] = NULL; 654 #endif 655 656 /* 657 * A collection of "global" variables used inside the kernel which 658 * are all collected in friostat_t via ioctl. 659 */ 660 kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[35].n_value, 661 sizeof(fiop->f_froute)); 662 kmemcpy((char *)&fiop->f_running, (u_long)deadlist[36].n_value, 663 sizeof(fiop->f_running)); 664 kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[37].n_value, 665 sizeof(fiop->f_groups)); 666 kmemcpy((char *)&fiop->f_active, (u_long)deadlist[38].n_value, 667 sizeof(fiop->f_active)); 668 kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[39].n_value, 669 sizeof(fiop->f_defpass)); 670 671 /* 672 * Build up the state information stats structure. 673 */ 674 kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp)); 675 kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp)); 676 ipsstp->iss_active = temp; 677 ipsstp->iss_table = (void *)deadlist[18].n_value; 678 ipsstp->iss_list = (void *)deadlist[17].n_value; 679 680 /* 681 * Build up the authentiation information stats structure. 682 */ 683 kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value, 684 sizeof(*frauthstp)); 685 frauthstp->fas_faelist = (void *)deadlist[1].n_value; 686 687 /* 688 * Build up the fragment information stats structure. 689 */ 690 kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value, 691 sizeof(*ifrstp)); 692 ifrstp->ifs_table = (void *)deadlist[23].n_value; 693 ifrstp->ifs_nattab = (void *)deadlist[24].n_value; 694 kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value, 695 sizeof(ifrstp->ifs_inuse)); 696 697 /* 698 * Get logging on/off switches 699 */ 700 kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value, 701 sizeof(state_logging)); 702 } 703 704 705 /* 706 * Display the kernel stats for packets blocked and passed and other 707 * associated running totals which are kept. 708 */ 709 static void showstats(fp, frf) 710 struct friostat *fp; 711 u_32_t frf; 712 { 713 714 PRINTF("bad packets:\t\tin %lu\tout %lu\n", 715 fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); 716 #ifdef USE_INET6 717 PRINTF(" IPv6 packets:\t\tin %lu out %lu\n", 718 fp->f_st[0].fr_ipv6, fp->f_st[1].fr_ipv6); 719 #endif 720 PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu", 721 fp->f_st[0].fr_block, fp->f_st[0].fr_pass, 722 fp->f_st[0].fr_nom); 723 PRINTF(" counted %lu short %lu\n", 724 fp->f_st[0].fr_acct, fp->f_st[0].fr_short); 725 PRINTF("output packets:\t\tblocked %lu passed %lu nomatch %lu", 726 fp->f_st[1].fr_block, fp->f_st[1].fr_pass, 727 fp->f_st[1].fr_nom); 728 PRINTF(" counted %lu short %lu\n", 729 fp->f_st[1].fr_acct, fp->f_st[1].fr_short); 730 PRINTF(" input packets logged:\tblocked %lu passed %lu\n", 731 fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); 732 PRINTF("output packets logged:\tblocked %lu passed %lu\n", 733 fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); 734 PRINTF(" packets logged:\tinput %lu output %lu\n", 735 fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl); 736 PRINTF(" log failures:\t\tinput %lu output %lu\n", 737 fp->f_st[0].fr_skip, fp->f_st[1].fr_skip); 738 PRINTF("fragment state(in):\tkept %lu\tlost %lu\tnot fragmented %lu\n", 739 fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr, 740 fp->f_st[0].fr_cfr); 741 PRINTF("fragment state(out):\tkept %lu\tlost %lu\tnot fragmented %lu\n", 742 fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr, 743 fp->f_st[0].fr_cfr); 744 PRINTF("packet state(in):\tkept %lu\tlost %lu\n", 745 fp->f_st[0].fr_ads, fp->f_st[0].fr_bads); 746 PRINTF("packet state(out):\tkept %lu\tlost %lu\n", 747 fp->f_st[1].fr_ads, fp->f_st[1].fr_bads); 748 PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n", 749 fp->f_st[0].fr_ret, fp->f_st[1].fr_ret); 750 PRINTF("Invalid source(in):\t%lu\n", fp->f_st[0].fr_badsrc); 751 PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n", 752 fp->f_st[0].fr_chit, fp->f_st[1].fr_chit); 753 PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n", 754 fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]); 755 PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n", 756 fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]); 757 PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n", 758 fp->f_froute[0], fp->f_froute[1]); 759 PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n", 760 fp->f_st[0].fr_tcpbad, fp->f_st[1].fr_tcpbad); 761 PRINTF("IPF Ticks:\t%lu\n", fp->f_ticks); 762 763 PRINTF("Packet log flags set: (%#x)\n", frf); 764 if (frf & FF_LOGPASS) 765 PRINTF("\tpackets passed through filter\n"); 766 if (frf & FF_LOGBLOCK) 767 PRINTF("\tpackets blocked by filter\n"); 768 if (frf & FF_LOGNOMATCH) 769 PRINTF("\tpackets not matched by filter\n"); 770 if (!frf) 771 PRINTF("\tnone\n"); 772 } 773 774 775 /* 776 * Print out a list of rules from the kernel, starting at the one passed. 777 */ 778 static void printlivelist(out, set, fp, group, comment) 779 int out, set; 780 frentry_t *fp; 781 char *group, *comment; 782 { 783 frgroup_t *grtop, *grtail, *g; 784 struct frentry fb, *fg; 785 int n; 786 ipfruleiter_t rule; 787 ipfobj_t obj; 788 789 fb.fr_next = fp; 790 n = 0; 791 792 grtop = NULL; 793 grtail = NULL; 794 rule.iri_ver = use_inet6? AF_INET6 : AF_INET; 795 rule.iri_inout = out; 796 rule.iri_active = set; 797 rule.iri_nrules = 1; 798 rule.iri_rule = &fb; 799 if (group != NULL) 800 strncpy(rule.iri_group, group, FR_GROUPLEN); 801 else 802 rule.iri_group[0] = '\0'; 803 804 bzero((char *)&obj, sizeof(obj)); 805 obj.ipfo_rev = IPFILTER_VERSION; 806 obj.ipfo_type = IPFOBJ_IPFITER; 807 obj.ipfo_size = sizeof(rule); 808 obj.ipfo_ptr = &rule; 809 810 do { 811 u_long array[1000]; 812 813 memset(array, 0xff, sizeof(array)); 814 fp = (frentry_t *)array; 815 rule.iri_rule = fp; 816 if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) { 817 perror("ioctl(SIOCIPFITER)"); 818 return; 819 } 820 if (fp->fr_data != NULL) 821 fp->fr_data = (char *)fp + sizeof(*fp); 822 823 n++; 824 825 if (opts & (OPT_HITS|OPT_VERBOSE)) 826 #ifdef USE_QUAD_T 827 PRINTF("%qu ", (unsigned long long) fp->fr_hits); 828 #else 829 PRINTF("%lu ", fp->fr_hits); 830 #endif 831 if (opts & (OPT_ACCNT|OPT_VERBOSE)) 832 #ifdef USE_QUAD_T 833 PRINTF("%qu ", (unsigned long long) fp->fr_bytes); 834 #else 835 PRINTF("%lu ", fp->fr_bytes); 836 #endif 837 if (opts & OPT_SHOWLINENO) 838 PRINTF("@%d ", n); 839 840 printfr(fp, ioctl); 841 if (opts & OPT_DEBUG) { 842 binprint(fp, sizeof(*fp)); 843 if (fp->fr_data != NULL && fp->fr_dsize > 0) 844 binprint(fp->fr_data, fp->fr_dsize); 845 } 846 847 if (fp->fr_grhead[0] != '\0') { 848 g = calloc(1, sizeof(*g)); 849 850 if (g != NULL) { 851 strncpy(g->fg_name, fp->fr_grhead, 852 FR_GROUPLEN); 853 if (grtop == NULL) { 854 grtop = g; 855 grtail = g; 856 } else { 857 grtail->fg_next = g; 858 grtail = g; 859 } 860 } 861 } 862 } while (fp->fr_next != NULL); 863 864 while ((g = grtop) != NULL) { 865 printlivelist(out, set, NULL, g->fg_name, comment); 866 grtop = g->fg_next; 867 free(g); 868 } 869 } 870 871 872 static void printdeadlist(out, set, fp, group, comment) 873 int out, set; 874 frentry_t *fp; 875 char *group, *comment; 876 { 877 frgroup_t *grtop, *grtail, *g; 878 struct frentry fb, *fg; 879 char *data; 880 u_32_t type; 881 int n; 882 883 fb.fr_next = fp; 884 n = 0; 885 grtop = NULL; 886 grtail = NULL; 887 888 do { 889 fp = fb.fr_next; 890 if (kmemcpy((char *)&fb, (u_long)fb.fr_next, 891 sizeof(fb)) == -1) { 892 perror("kmemcpy"); 893 return; 894 } 895 896 data = NULL; 897 type = fb.fr_type & ~FR_T_BUILTIN; 898 if (type == FR_T_IPF || type == FR_T_BPFOPC) { 899 if (fb.fr_dsize) { 900 data = malloc(fb.fr_dsize); 901 902 if (kmemcpy(data, (u_long)fb.fr_data, 903 fb.fr_dsize) == -1) { 904 perror("kmemcpy"); 905 return; 906 } 907 fb.fr_data = data; 908 } 909 } 910 911 n++; 912 913 if (opts & (OPT_HITS|OPT_VERBOSE)) 914 #ifdef USE_QUAD_T 915 PRINTF("%qu ", (unsigned long long) fb.fr_hits); 916 #else 917 PRINTF("%lu ", fb.fr_hits); 918 #endif 919 if (opts & (OPT_ACCNT|OPT_VERBOSE)) 920 #ifdef USE_QUAD_T 921 PRINTF("%qu ", (unsigned long long) fb.fr_bytes); 922 #else 923 PRINTF("%lu ", fb.fr_bytes); 924 #endif 925 if (opts & OPT_SHOWLINENO) 926 PRINTF("@%d ", n); 927 928 printfr(fp, ioctl); 929 if (opts & OPT_DEBUG) { 930 binprint(fp, sizeof(*fp)); 931 if (fb.fr_data != NULL && fb.fr_dsize > 0) 932 binprint(fb.fr_data, fb.fr_dsize); 933 } 934 if (data != NULL) 935 free(data); 936 if (fb.fr_grhead[0] != '\0') { 937 g = calloc(1, sizeof(*g)); 938 939 if (g != NULL) { 940 strncpy(g->fg_name, fb.fr_grhead, 941 FR_GROUPLEN); 942 if (grtop == NULL) { 943 grtop = g; 944 grtail = g; 945 } else { 946 grtail->fg_next = g; 947 grtail = g; 948 } 949 } 950 } 951 if (type == FR_T_CALLFUNC) { 952 printdeadlist(out, set, fb.fr_data, group, 953 "# callfunc: "); 954 } 955 } while (fb.fr_next != NULL); 956 957 while ((g = grtop) != NULL) { 958 printdeadlist(out, set, NULL, g->fg_name, comment); 959 grtop = g->fg_next; 960 free(g); 961 } 962 } 963 964 965 /* 966 * print out all of the asked for rule sets, using the stats struct as 967 * the base from which to get the pointers. 968 */ 969 static void showlist(fiop) 970 struct friostat *fiop; 971 { 972 struct frentry *fp = NULL; 973 int i, set; 974 975 set = fiop->f_active; 976 if (opts & OPT_INACTIVE) 977 set = 1 - set; 978 if (opts & OPT_ACCNT) { 979 #ifdef USE_INET6 980 if ((use_inet6) && (opts & OPT_OUTQUE)) { 981 i = F_ACOUT; 982 fp = (struct frentry *)fiop->f_acctout6[set]; 983 } else if ((use_inet6) && (opts & OPT_INQUE)) { 984 i = F_ACIN; 985 fp = (struct frentry *)fiop->f_acctin6[set]; 986 } else 987 #endif 988 if (opts & OPT_OUTQUE) { 989 i = F_ACOUT; 990 fp = (struct frentry *)fiop->f_acctout[set]; 991 } else if (opts & OPT_INQUE) { 992 i = F_ACIN; 993 fp = (struct frentry *)fiop->f_acctin[set]; 994 } else { 995 FPRINTF(stderr, "No -i or -o given with -a\n"); 996 return; 997 } 998 } else { 999 #ifdef USE_INET6 1000 if ((use_inet6) && (opts & OPT_OUTQUE)) { 1001 i = F_OUT; 1002 fp = (struct frentry *)fiop->f_fout6[set]; 1003 } else if ((use_inet6) && (opts & OPT_INQUE)) { 1004 i = F_IN; 1005 fp = (struct frentry *)fiop->f_fin6[set]; 1006 } else 1007 #endif 1008 if (opts & OPT_OUTQUE) { 1009 i = F_OUT; 1010 fp = (struct frentry *)fiop->f_fout[set]; 1011 } else if (opts & OPT_INQUE) { 1012 i = F_IN; 1013 fp = (struct frentry *)fiop->f_fin[set]; 1014 } else 1015 return; 1016 } 1017 if (opts & OPT_VERBOSE) 1018 FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i); 1019 1020 if (opts & OPT_VERBOSE) 1021 PRINTF("fp %p set %d\n", fp, set); 1022 if (!fp) { 1023 FPRINTF(stderr, "empty list for %s%s\n", 1024 (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]); 1025 return; 1026 } 1027 if (live_kernel == 1) 1028 printlivelist(i, set, fp, NULL, NULL); 1029 else 1030 printdeadlist(i, set, fp, NULL, NULL); 1031 } 1032 1033 1034 /* 1035 * Display ipfilter stateful filtering information 1036 */ 1037 static void showipstates(ipsp) 1038 ips_stat_t *ipsp; 1039 { 1040 u_long minlen, maxlen, totallen, *buckets; 1041 int i, sz; 1042 1043 sz = sizeof(*buckets) * ipsp->iss_statesize; 1044 buckets = (u_long *)malloc(sz); 1045 if (buckets == NULL) { 1046 perror("malloc"); 1047 exit(1); 1048 } 1049 if (kmemcpy((char *)buckets, (u_long)ipsp->iss_bucketlen, sz)) { 1050 free(buckets); 1051 return; 1052 } 1053 1054 /* 1055 * If a list of states hasn't been asked for, only print out stats 1056 */ 1057 if (!(opts & OPT_SHOWLIST)) { 1058 PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n", 1059 ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp); 1060 PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits, 1061 ipsp->iss_miss); 1062 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu max bucket\n", 1063 ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_bucketfull); 1064 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu bkts in use\n", 1065 ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse); 1066 PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n", 1067 ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin); 1068 1069 PRINTF("State logging %sabled\n", 1070 state_logging ? "en" : "dis"); 1071 1072 PRINTF("\nState table bucket statistics:\n"); 1073 PRINTF("\t%lu in use\t\n", ipsp->iss_inuse); 1074 1075 minlen = ipsp->iss_max; 1076 totallen = 0; 1077 maxlen = 0; 1078 1079 for (i = 0; i < ipsp->iss_statesize; i++) { 1080 if (buckets[i] > maxlen) 1081 maxlen = buckets[i]; 1082 if (buckets[i] < minlen) 1083 minlen = buckets[i]; 1084 totallen += buckets[i]; 1085 } 1086 1087 PRINTF("\t%2.2f%% bucket usage\n\t%lu minimal length\n", 1088 ((float)ipsp->iss_inuse / ipsp->iss_statesize) * 100.0, 1089 minlen); 1090 PRINTF("\t%lu maximal length\n\t%.3f average length\n", 1091 maxlen, 1092 ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse : 1093 0.0); 1094 1095 #define ENTRIES_PER_LINE 5 1096 1097 if (opts & OPT_VERBOSE) { 1098 PRINTF("\nCurrent bucket sizes :\n"); 1099 for (i = 0; i < ipsp->iss_statesize; i++) { 1100 if ((i % ENTRIES_PER_LINE) == 0) 1101 PRINTF("\t"); 1102 PRINTF("%4d -> %4lu", i, buckets[i]); 1103 if ((i % ENTRIES_PER_LINE) == 1104 (ENTRIES_PER_LINE - 1)) 1105 PRINTF("\n"); 1106 else 1107 PRINTF(" "); 1108 } 1109 PRINTF("\n"); 1110 } 1111 PRINTF("\n"); 1112 1113 free(buckets); 1114 return; 1115 } 1116 1117 /* 1118 * Print out all the state information currently held in the kernel. 1119 */ 1120 while (ipsp->iss_list != NULL) { 1121 ipsp->iss_list = printstate(ipsp->iss_list, opts, 1122 ipsp->iss_ticks); 1123 } 1124 1125 free(buckets); 1126 } 1127 1128 1129 #ifdef STATETOP 1130 static int handle_resize = 0, handle_break = 0; 1131 1132 static void topipstates(saddr, daddr, sport, dport, protocol, ver, 1133 refreshtime, topclosed) 1134 i6addr_t saddr; 1135 i6addr_t daddr; 1136 int sport; 1137 int dport; 1138 int protocol; 1139 int ver; 1140 int refreshtime; 1141 int topclosed; 1142 { 1143 char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE]; 1144 int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT; 1145 int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0; 1146 int len, srclen, dstlen, forward = 1, c = 0; 1147 ips_stat_t ipsst, *ipsstp = &ipsst; 1148 statetop_t *tstable = NULL, *tp; 1149 const char *errstr = ""; 1150 ipstate_t ips; 1151 ipfobj_t ipfo; 1152 struct timeval selecttimeout; 1153 char hostnm[HOSTNMLEN]; 1154 struct protoent *proto; 1155 fd_set readfd; 1156 time_t t; 1157 1158 /* install signal handlers */ 1159 signal(SIGINT, sig_break); 1160 signal(SIGQUIT, sig_break); 1161 signal(SIGTERM, sig_break); 1162 signal(SIGWINCH, sig_resize); 1163 1164 /* init ncurses stuff */ 1165 initscr(); 1166 cbreak(); 1167 noecho(); 1168 curs_set(0); 1169 timeout(0); 1170 getmaxyx(stdscr, maxy, maxx); 1171 1172 /* init hostname */ 1173 gethostname(hostnm, sizeof(hostnm) - 1); 1174 hostnm[sizeof(hostnm) - 1] = '\0'; 1175 1176 /* init ipfobj_t stuff */ 1177 bzero((caddr_t)&ipfo, sizeof(ipfo)); 1178 ipfo.ipfo_rev = IPFILTER_VERSION; 1179 ipfo.ipfo_size = sizeof(*ipsstp); 1180 ipfo.ipfo_ptr = (void *)ipsstp; 1181 ipfo.ipfo_type = IPFOBJ_STATESTAT; 1182 1183 /* repeat until user aborts */ 1184 while ( 1 ) { 1185 1186 /* get state table */ 1187 bzero((char *)&ipsst, sizeof(ipsst)); 1188 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { 1189 errstr = "ioctl(SIOCGETFS)"; 1190 ret = -1; 1191 goto out; 1192 } 1193 1194 /* clear the history */ 1195 tsentry = -1; 1196 1197 /* reset max str len */ 1198 srclen = dstlen = 0; 1199 1200 /* read the state table and store in tstable */ 1201 for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) { 1202 1203 if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list, 1204 sizeof(ips))) 1205 break; 1206 1207 if (ips.is_v != ver) 1208 continue; 1209 1210 /* check v4 src/dest addresses */ 1211 if (ips.is_v == 4) { 1212 if ((saddr.in4.s_addr != INADDR_ANY && 1213 saddr.in4.s_addr != ips.is_saddr) || 1214 (daddr.in4.s_addr != INADDR_ANY && 1215 daddr.in4.s_addr != ips.is_daddr)) 1216 continue; 1217 } 1218 #ifdef USE_INET6 1219 /* check v6 src/dest addresses */ 1220 if (ips.is_v == 6) { 1221 if ((IP6_NEQ(&saddr, &in6addr_any) && 1222 IP6_NEQ(&saddr, &ips.is_src)) || 1223 (IP6_NEQ(&daddr, &in6addr_any) && 1224 IP6_NEQ(&daddr, &ips.is_dst))) 1225 continue; 1226 } 1227 #endif 1228 /* check protocol */ 1229 if (protocol > 0 && protocol != ips.is_p) 1230 continue; 1231 1232 /* check ports if protocol is TCP or UDP */ 1233 if (((ips.is_p == IPPROTO_TCP) || 1234 (ips.is_p == IPPROTO_UDP)) && 1235 (((sport > 0) && (htons(sport) != ips.is_sport)) || 1236 ((dport > 0) && (htons(dport) != ips.is_dport)))) 1237 continue; 1238 1239 /* show closed TCP sessions ? */ 1240 if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) && 1241 (ips.is_state[0] >= IPF_TCPS_LAST_ACK) && 1242 (ips.is_state[1] >= IPF_TCPS_LAST_ACK)) 1243 continue; 1244 1245 /* 1246 * if necessary make room for this state 1247 * entry 1248 */ 1249 tsentry++; 1250 if (!maxtsentries || tsentry == maxtsentries) { 1251 maxtsentries += STGROWSIZE; 1252 tstable = realloc(tstable, 1253 maxtsentries * sizeof(statetop_t)); 1254 if (tstable == NULL) { 1255 perror("realloc"); 1256 exit(-1); 1257 } 1258 } 1259 1260 /* get max src/dest address string length */ 1261 len = strlen(getip(ips.is_v, &ips.is_src)); 1262 if (srclen < len) 1263 srclen = len; 1264 len = strlen(getip(ips.is_v, &ips.is_dst)); 1265 if (dstlen < len) 1266 dstlen = len; 1267 1268 /* fill structure */ 1269 tp = tstable + tsentry; 1270 tp->st_src = ips.is_src; 1271 tp->st_dst = ips.is_dst; 1272 tp->st_p = ips.is_p; 1273 tp->st_v = ips.is_v; 1274 tp->st_state[0] = ips.is_state[0]; 1275 tp->st_state[1] = ips.is_state[1]; 1276 if (forward) { 1277 tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1]; 1278 tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1]; 1279 } else { 1280 tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3]; 1281 tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3]; 1282 } 1283 tp->st_age = ips.is_die - ipsstp->iss_ticks; 1284 if ((ips.is_p == IPPROTO_TCP) || 1285 (ips.is_p == IPPROTO_UDP)) { 1286 tp->st_sport = ips.is_sport; 1287 tp->st_dport = ips.is_dport; 1288 } 1289 } 1290 1291 1292 /* sort the array */ 1293 if (tsentry != -1) { 1294 switch (sorting) 1295 { 1296 case STSORT_PR: 1297 qsort(tstable, tsentry + 1, 1298 sizeof(statetop_t), sort_p); 1299 break; 1300 case STSORT_PKTS: 1301 qsort(tstable, tsentry + 1, 1302 sizeof(statetop_t), sort_pkts); 1303 break; 1304 case STSORT_BYTES: 1305 qsort(tstable, tsentry + 1, 1306 sizeof(statetop_t), sort_bytes); 1307 break; 1308 case STSORT_TTL: 1309 qsort(tstable, tsentry + 1, 1310 sizeof(statetop_t), sort_ttl); 1311 break; 1312 case STSORT_SRCIP: 1313 qsort(tstable, tsentry + 1, 1314 sizeof(statetop_t), sort_srcip); 1315 break; 1316 case STSORT_SRCPT: 1317 qsort(tstable, tsentry +1, 1318 sizeof(statetop_t), sort_srcpt); 1319 break; 1320 case STSORT_DSTIP: 1321 qsort(tstable, tsentry + 1, 1322 sizeof(statetop_t), sort_dstip); 1323 break; 1324 case STSORT_DSTPT: 1325 qsort(tstable, tsentry + 1, 1326 sizeof(statetop_t), sort_dstpt); 1327 break; 1328 default: 1329 break; 1330 } 1331 } 1332 1333 /* handle window resizes */ 1334 if (handle_resize) { 1335 endwin(); 1336 initscr(); 1337 cbreak(); 1338 noecho(); 1339 curs_set(0); 1340 timeout(0); 1341 getmaxyx(stdscr, maxy, maxx); 1342 redraw = 1; 1343 handle_resize = 0; 1344 } 1345 1346 /* stop program? */ 1347 if (handle_break) 1348 break; 1349 1350 /* print title */ 1351 erase(); 1352 attron(A_BOLD); 1353 winy = 0; 1354 move(winy,0); 1355 sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION); 1356 for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++) 1357 printw(" "); 1358 printw("%s", str1); 1359 attroff(A_BOLD); 1360 1361 /* just for fun add a clock */ 1362 move(winy, maxx - 8); 1363 t = time(NULL); 1364 strftime(str1, 80, "%T", localtime(&t)); 1365 printw("%s\n", str1); 1366 1367 /* 1368 * print the display filters, this is placed in the loop, 1369 * because someday I might add code for changing these 1370 * while the programming is running :-) 1371 */ 1372 if (sport >= 0) 1373 sprintf(str1, "%s,%d", getip(ver, &saddr), sport); 1374 else 1375 sprintf(str1, "%s", getip(ver, &saddr)); 1376 1377 if (dport >= 0) 1378 sprintf(str2, "%s,%d", getip(ver, &daddr), dport); 1379 else 1380 sprintf(str2, "%s", getip(ver, &daddr)); 1381 1382 if (protocol < 0) 1383 strcpy(str3, "any"); 1384 else if ((proto = getprotobynumber(protocol)) != NULL) 1385 sprintf(str3, "%s", proto->p_name); 1386 else 1387 sprintf(str3, "%d", protocol); 1388 1389 switch (sorting) 1390 { 1391 case STSORT_PR: 1392 sprintf(str4, "proto"); 1393 break; 1394 case STSORT_PKTS: 1395 sprintf(str4, "# pkts"); 1396 break; 1397 case STSORT_BYTES: 1398 sprintf(str4, "# bytes"); 1399 break; 1400 case STSORT_TTL: 1401 sprintf(str4, "ttl"); 1402 break; 1403 case STSORT_SRCIP: 1404 sprintf(str4, "src ip"); 1405 break; 1406 case STSORT_SRCPT: 1407 sprintf(str4, "src port"); 1408 break; 1409 case STSORT_DSTIP: 1410 sprintf(str4, "dest ip"); 1411 break; 1412 case STSORT_DSTPT: 1413 sprintf(str4, "dest port"); 1414 break; 1415 default: 1416 sprintf(str4, "unknown"); 1417 break; 1418 } 1419 1420 if (reverse) 1421 strcat(str4, " (reverse)"); 1422 1423 winy += 2; 1424 move(winy,0); 1425 printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n", 1426 str1, str2, str3, str4); 1427 1428 /* 1429 * For an IPv4 IP address we need at most 15 characters, 1430 * 4 tuples of 3 digits, separated by 3 dots. Enforce this 1431 * length, so the colums do not change positions based 1432 * on the size of the IP address. This length makes the 1433 * output fit in a 80 column terminal. 1434 * We are lacking a good solution for IPv6 addresses (that 1435 * can be longer that 15 characters), so we do not enforce 1436 * a maximum on the IP field size. 1437 */ 1438 if (srclen < 15) 1439 srclen = 15; 1440 if (dstlen < 15) 1441 dstlen = 15; 1442 1443 /* print column description */ 1444 winy += 2; 1445 move(winy,0); 1446 attron(A_BOLD); 1447 printw("%-*s %-*s %3s %4s %7s %9s %9s\n", 1448 srclen + 6, "Source IP", dstlen + 6, "Destination IP", 1449 "ST", "PR", "#pkts", "#bytes", "ttl"); 1450 attroff(A_BOLD); 1451 1452 /* print all the entries */ 1453 tp = tstable; 1454 if (reverse) 1455 tp += tsentry; 1456 1457 if (tsentry > maxy - 6) 1458 tsentry = maxy - 6; 1459 for (i = 0; i <= tsentry; i++) { 1460 /* print src/dest and port */ 1461 if ((tp->st_p == IPPROTO_TCP) || 1462 (tp->st_p == IPPROTO_UDP)) { 1463 sprintf(str1, "%s,%hu", 1464 getip(tp->st_v, &tp->st_src), 1465 ntohs(tp->st_sport)); 1466 sprintf(str2, "%s,%hu", 1467 getip(tp->st_v, &tp->st_dst), 1468 ntohs(tp->st_dport)); 1469 } else { 1470 sprintf(str1, "%s", getip(tp->st_v, 1471 &tp->st_src)); 1472 sprintf(str2, "%s", getip(tp->st_v, 1473 &tp->st_dst)); 1474 } 1475 winy++; 1476 move(winy, 0); 1477 printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2); 1478 1479 /* print state */ 1480 sprintf(str1, "%X/%X", tp->st_state[0], 1481 tp->st_state[1]); 1482 printw(" %3s", str1); 1483 1484 /* print protocol */ 1485 proto = getprotobynumber(tp->st_p); 1486 if (proto) { 1487 strncpy(str1, proto->p_name, 4); 1488 str1[4] = '\0'; 1489 } else { 1490 sprintf(str1, "%d", tp->st_p); 1491 } 1492 /* just print icmp for IPv6-ICMP */ 1493 if (tp->st_p == IPPROTO_ICMPV6) 1494 strcpy(str1, "icmp"); 1495 printw(" %4s", str1); 1496 1497 /* print #pkt/#bytes */ 1498 #ifdef USE_QUAD_T 1499 printw(" %7qu %9qu", (unsigned long long) tp->st_pkts, 1500 (unsigned long long) tp->st_bytes); 1501 #else 1502 printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes); 1503 #endif 1504 printw(" %9s", ttl_to_string(tp->st_age)); 1505 1506 if (reverse) 1507 tp--; 1508 else 1509 tp++; 1510 } 1511 1512 /* screen data structure is filled, now update the screen */ 1513 if (redraw) 1514 clearok(stdscr,1); 1515 1516 if (refresh() == ERR) 1517 break; 1518 if (redraw) { 1519 clearok(stdscr,0); 1520 redraw = 0; 1521 } 1522 1523 /* wait for key press or a 1 second time out period */ 1524 selecttimeout.tv_sec = refreshtime; 1525 selecttimeout.tv_usec = 0; 1526 FD_ZERO(&readfd); 1527 FD_SET(0, &readfd); 1528 select(1, &readfd, NULL, NULL, &selecttimeout); 1529 1530 /* if key pressed, read all waiting keys */ 1531 if (FD_ISSET(0, &readfd)) { 1532 c = wgetch(stdscr); 1533 if (c == ERR) 1534 continue; 1535 1536 if (ISALPHA(c) && ISUPPER(c)) 1537 c = TOLOWER(c); 1538 if (c == 'l') { 1539 redraw = 1; 1540 } else if (c == 'q') { 1541 break; 1542 } else if (c == 'r') { 1543 reverse = !reverse; 1544 } else if (c == 'b') { 1545 forward = 0; 1546 } else if (c == 'f') { 1547 forward = 1; 1548 } else if (c == 's') { 1549 if (++sorting > STSORT_MAX) 1550 sorting = 0; 1551 } 1552 } 1553 } /* while */ 1554 1555 out: 1556 printw("\n"); 1557 refresh(); 1558 endwin(); 1559 free(tstable); 1560 if (ret != 0) 1561 perror(errstr); 1562 } 1563 #endif 1564 1565 1566 /* 1567 * Show fragment cache information that's held in the kernel. 1568 */ 1569 static void showfrstates(ifsp) 1570 ipfrstat_t *ifsp; 1571 { 1572 struct ipfr *ipfrtab[IPFT_SIZE], ifr; 1573 int i; 1574 1575 /* 1576 * print out the numeric statistics 1577 */ 1578 PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n", 1579 ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits); 1580 PRINTF("\t%lu retrans\n\t%lu too short\n", 1581 ifsp->ifs_retrans0, ifsp->ifs_short); 1582 PRINTF("\t%lu no memory\n\t%lu already exist\n", 1583 ifsp->ifs_nomem, ifsp->ifs_exists); 1584 PRINTF("\t%lu inuse\n", ifsp->ifs_inuse); 1585 if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab))) 1586 return; 1587 1588 /* 1589 * Print out the contents (if any) of the fragment cache table. 1590 */ 1591 PRINTF("\n"); 1592 for (i = 0; i < IPFT_SIZE; i++) 1593 while (ipfrtab[i] != NULL) { 1594 if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], 1595 sizeof(ifr)) == -1) 1596 break; 1597 printfraginfo("", &ifr); 1598 ipfrtab[i] = ifr.ipfr_next; 1599 } 1600 /* 1601 * Print out the contents (if any) of the NAT fragment cache table. 1602 */ 1603 if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,sizeof(ipfrtab))) 1604 return; 1605 for (i = 0; i < IPFT_SIZE; i++) 1606 while (ipfrtab[i] != NULL) { 1607 if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], 1608 sizeof(ifr)) == -1) 1609 break; 1610 printfraginfo("NAT: ", &ifr); 1611 ipfrtab[i] = ifr.ipfr_next; 1612 } 1613 } 1614 1615 1616 /* 1617 * Show stats on how auth within IPFilter has been used 1618 */ 1619 static void showauthstates(asp) 1620 fr_authstat_t *asp; 1621 { 1622 frauthent_t *frap, fra; 1623 1624 #ifdef USE_QUAD_T 1625 printf("Authorisation hits: %qu\tmisses %qu\n", 1626 (unsigned long long) asp->fas_hits, 1627 (unsigned long long) asp->fas_miss); 1628 #else 1629 printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits, 1630 asp->fas_miss); 1631 #endif 1632 printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n", 1633 asp->fas_nospace, asp->fas_added, asp->fas_sendfail, 1634 asp->fas_sendok); 1635 printf("queok %ld\nquefail %ld\nexpire %ld\n", 1636 asp->fas_queok, asp->fas_quefail, asp->fas_expire); 1637 1638 frap = asp->fas_faelist; 1639 while (frap) { 1640 if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1) 1641 break; 1642 1643 printf("age %ld\t", fra.fae_age); 1644 printfr(&fra.fae_fr, ioctl); 1645 frap = fra.fae_next; 1646 } 1647 } 1648 1649 1650 /* 1651 * Display groups used for each of filter rules, accounting rules and 1652 * authentication, separately. 1653 */ 1654 static void showgroups(fiop) 1655 struct friostat *fiop; 1656 { 1657 static char *gnames[3] = { "Filter", "Accounting", "Authentication" }; 1658 static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH }; 1659 frgroup_t *fp, grp; 1660 int on, off, i; 1661 1662 on = fiop->f_active; 1663 off = 1 - on; 1664 1665 for (i = 0; i < 3; i++) { 1666 printf("%s groups (active):\n", gnames[i]); 1667 for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL; 1668 fp = grp.fg_next) 1669 if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) 1670 break; 1671 else 1672 printf("%s\n", grp.fg_name); 1673 printf("%s groups (inactive):\n", gnames[i]); 1674 for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL; 1675 fp = grp.fg_next) 1676 if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) 1677 break; 1678 else 1679 printf("%s\n", grp.fg_name); 1680 } 1681 } 1682 1683 static void parse_ipportstr(argument, ip, port) 1684 const char *argument; 1685 i6addr_t *ip; 1686 int *port; 1687 { 1688 char *s, *comma; 1689 int ok = 0; 1690 1691 /* make working copy of argument, Theoretically you must be able 1692 * to write to optarg, but that seems very ugly to me.... 1693 */ 1694 s = strdup(argument); 1695 if (s == NULL) 1696 return; 1697 1698 /* get port */ 1699 if ((comma = strchr(s, ',')) != NULL) { 1700 if (!strcasecmp(comma + 1, "any")) { 1701 *port = -1; 1702 } else if (!sscanf(comma + 1, "%d", port) || 1703 (*port < 0) || (*port > 65535)) { 1704 fprintf(stderr, "Invalid port specfication in %s\n", 1705 argument); 1706 free(s); 1707 exit(-2); 1708 } 1709 *comma = '\0'; 1710 } 1711 1712 1713 /* get ip address */ 1714 if (!strcasecmp(s, "any")) { 1715 ip->in4.s_addr = INADDR_ANY; 1716 #ifdef USE_INET6 1717 ip->in6 = in6addr_any; 1718 } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) { 1719 ok = 1; 1720 #endif 1721 } else if (inet_aton(s, &ip->in4)) 1722 ok = 1; 1723 1724 if (ok == 0) { 1725 fprintf(stderr, "Invalid IP address: %s\n", s); 1726 free(s); 1727 exit(-2); 1728 } 1729 1730 /* free allocated memory */ 1731 free(s); 1732 } 1733 1734 1735 #ifdef STATETOP 1736 static void sig_resize(s) 1737 int s; 1738 { 1739 handle_resize = 1; 1740 } 1741 1742 static void sig_break(s) 1743 int s; 1744 { 1745 handle_break = 1; 1746 } 1747 1748 static char *getip(v, addr) 1749 int v; 1750 i6addr_t *addr; 1751 { 1752 #ifdef USE_INET6 1753 static char hostbuf[MAXHOSTNAMELEN+1]; 1754 #endif 1755 1756 if (v == 4) 1757 return inet_ntoa(addr->in4); 1758 1759 #ifdef USE_INET6 1760 (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1); 1761 hostbuf[MAXHOSTNAMELEN] = '\0'; 1762 return hostbuf; 1763 #else 1764 return "IPv6"; 1765 #endif 1766 } 1767 1768 1769 static char *ttl_to_string(ttl) 1770 long int ttl; 1771 { 1772 static char ttlbuf[STSTRSIZE]; 1773 int hours, minutes, seconds; 1774 1775 /* ttl is in half seconds */ 1776 ttl /= 2; 1777 1778 hours = ttl / 3600; 1779 ttl = ttl % 3600; 1780 minutes = ttl / 60; 1781 seconds = ttl % 60; 1782 1783 if (hours > 0) 1784 sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds); 1785 else 1786 sprintf(ttlbuf, "%2d:%02d", minutes, seconds); 1787 return ttlbuf; 1788 } 1789 1790 1791 static int sort_pkts(a, b) 1792 const void *a; 1793 const void *b; 1794 { 1795 1796 register const statetop_t *ap = a; 1797 register const statetop_t *bp = b; 1798 1799 if (ap->st_pkts == bp->st_pkts) 1800 return 0; 1801 else if (ap->st_pkts < bp->st_pkts) 1802 return 1; 1803 return -1; 1804 } 1805 1806 1807 static int sort_bytes(a, b) 1808 const void *a; 1809 const void *b; 1810 { 1811 register const statetop_t *ap = a; 1812 register const statetop_t *bp = b; 1813 1814 if (ap->st_bytes == bp->st_bytes) 1815 return 0; 1816 else if (ap->st_bytes < bp->st_bytes) 1817 return 1; 1818 return -1; 1819 } 1820 1821 1822 static int sort_p(a, b) 1823 const void *a; 1824 const void *b; 1825 { 1826 register const statetop_t *ap = a; 1827 register const statetop_t *bp = b; 1828 1829 if (ap->st_p == bp->st_p) 1830 return 0; 1831 else if (ap->st_p < bp->st_p) 1832 return 1; 1833 return -1; 1834 } 1835 1836 1837 static int sort_ttl(a, b) 1838 const void *a; 1839 const void *b; 1840 { 1841 register const statetop_t *ap = a; 1842 register const statetop_t *bp = b; 1843 1844 if (ap->st_age == bp->st_age) 1845 return 0; 1846 else if (ap->st_age < bp->st_age) 1847 return 1; 1848 return -1; 1849 } 1850 1851 static int sort_srcip(a, b) 1852 const void *a; 1853 const void *b; 1854 { 1855 register const statetop_t *ap = a; 1856 register const statetop_t *bp = b; 1857 1858 #ifdef USE_INET6 1859 if (use_inet6) { 1860 if (IP6_EQ(&ap->st_src, &bp->st_src)) 1861 return 0; 1862 else if (IP6_GT(&ap->st_src, &bp->st_src)) 1863 return 1; 1864 } else 1865 #endif 1866 { 1867 if (ntohl(ap->st_src.in4.s_addr) == 1868 ntohl(bp->st_src.in4.s_addr)) 1869 return 0; 1870 else if (ntohl(ap->st_src.in4.s_addr) > 1871 ntohl(bp->st_src.in4.s_addr)) 1872 return 1; 1873 } 1874 return -1; 1875 } 1876 1877 static int sort_srcpt(a, b) 1878 const void *a; 1879 const void *b; 1880 { 1881 register const statetop_t *ap = a; 1882 register const statetop_t *bp = b; 1883 1884 if (htons(ap->st_sport) == htons(bp->st_sport)) 1885 return 0; 1886 else if (htons(ap->st_sport) > htons(bp->st_sport)) 1887 return 1; 1888 return -1; 1889 } 1890 1891 static int sort_dstip(a, b) 1892 const void *a; 1893 const void *b; 1894 { 1895 register const statetop_t *ap = a; 1896 register const statetop_t *bp = b; 1897 1898 #ifdef USE_INET6 1899 if (use_inet6) { 1900 if (IP6_EQ(&ap->st_dst, &bp->st_dst)) 1901 return 0; 1902 else if (IP6_GT(&ap->st_dst, &bp->st_dst)) 1903 return 1; 1904 } else 1905 #endif 1906 { 1907 if (ntohl(ap->st_dst.in4.s_addr) == 1908 ntohl(bp->st_dst.in4.s_addr)) 1909 return 0; 1910 else if (ntohl(ap->st_dst.in4.s_addr) > 1911 ntohl(bp->st_dst.in4.s_addr)) 1912 return 1; 1913 } 1914 return -1; 1915 } 1916 1917 static int sort_dstpt(a, b) 1918 const void *a; 1919 const void *b; 1920 { 1921 register const statetop_t *ap = a; 1922 register const statetop_t *bp = b; 1923 1924 if (htons(ap->st_dport) == htons(bp->st_dport)) 1925 return 0; 1926 else if (htons(ap->st_dport) > htons(bp->st_dport)) 1927 return 1; 1928 return -1; 1929 } 1930 1931 #endif 1932