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