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", ipsp->iss_hits, 1059 ipsp->iss_miss); 1060 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu max bucket\n", 1061 ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_bucketfull); 1062 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu bkts in use\n", 1063 ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse); 1064 PRINTF("\t%lu active\n\t%lu expired\n", 1065 ipsp->iss_active, ipsp->iss_expire); 1066 PRINTF("\t%lu closed\n\t%u orphans\n", 1067 ipsp->iss_fin, ipsp->iss_orphans); 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