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