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 #define F_IN 0 93 #define F_OUT 1 94 #define F_ACIN 2 95 #define F_ACOUT 3 96 static char *filters[4] = { "ipfilter(in)", "ipfilter(out)", 97 "ipacct(in)", "ipacct(out)" }; 98 static int state_logging = -1; 99 100 int opts = 0; 101 int use_inet6 = 0; 102 int live_kernel = 1; 103 int state_fd = -1; 104 int ipf_fd = -1; 105 106 #ifdef STATETOP 107 #define STSTRSIZE 80 108 #define STGROWSIZE 16 109 #define HOSTNMLEN 40 110 111 #define STSORT_PR 0 112 #define STSORT_PKTS 1 113 #define STSORT_BYTES 2 114 #define STSORT_TTL 3 115 #define STSORT_SRCIP 4 116 #define STSORT_SRCPT 5 117 #define STSORT_DSTIP 6 118 #define STSORT_DSTPT 7 119 #define STSORT_MAX STSORT_DSTPT 120 #define STSORT_DEFAULT STSORT_BYTES 121 122 123 typedef struct statetop { 124 i6addr_t st_src; 125 i6addr_t st_dst; 126 u_short st_sport; 127 u_short st_dport; 128 u_char st_p; 129 u_char st_v; 130 u_char st_state[2]; 131 U_QUAD_T st_pkts; 132 U_QUAD_T st_bytes; 133 u_long st_age; 134 } statetop_t; 135 #endif 136 137 int main __P((int, char *[])); 138 139 static void showstats __P((friostat_t *, u_32_t)); 140 static void showfrstates __P((ipfrstat_t *)); 141 static void showlist __P((friostat_t *)); 142 static void showipstates __P((ips_stat_t *)); 143 static void showauthstates __P((fr_authstat_t *)); 144 static void showgroups __P((friostat_t *)); 145 static void usage __P((char *)); 146 static void printlivelist __P((int, int, frentry_t *, char *, char *)); 147 static void printdeadlist __P((int, int, frentry_t *, char *, char *)); 148 static void printlist __P((frentry_t *, char *)); 149 static void parse_ipportstr __P((const char *, i6addr_t *, int *)); 150 static void ipfstate_live __P((char *, friostat_t **, ips_stat_t **, 151 ipfrstat_t **, fr_authstat_t **, u_32_t *)); 152 static void ipfstate_dead __P((char *, friostat_t **, ips_stat_t **, 153 ipfrstat_t **, fr_authstat_t **, u_32_t *)); 154 #ifdef STATETOP 155 static void topipstates __P((i6addr_t, i6addr_t, int, int, int, 156 int, int, int)); 157 static void sig_break __P((int)); 158 static void sig_resize __P((int)); 159 static char *getip __P((int, i6addr_t *)); 160 static char *ttl_to_string __P((long)); 161 static int sort_p __P((const void *, const void *)); 162 static int sort_pkts __P((const void *, const void *)); 163 static int sort_bytes __P((const void *, const void *)); 164 static int sort_ttl __P((const void *, const void *)); 165 static int sort_srcip __P((const void *, const void *)); 166 static int sort_srcpt __P((const void *, const void *)); 167 static int sort_dstip __P((const void *, const void *)); 168 static int sort_dstpt __P((const void *, const void *)); 169 #endif 170 171 172 static void usage(name) 173 char *name; 174 { 175 #ifdef USE_INET6 176 fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name); 177 #else 178 fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name); 179 #endif 180 fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name); 181 #ifdef USE_INET6 182 fprintf(stderr, " %s -t [-6C] ", name); 183 #else 184 fprintf(stderr, " %s -t [-C] ", name); 185 #endif 186 fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n"); 187 exit(1); 188 } 189 190 191 int main(argc,argv) 192 int argc; 193 char *argv[]; 194 { 195 fr_authstat_t frauthst; 196 fr_authstat_t *frauthstp = &frauthst; 197 friostat_t fio; 198 friostat_t *fiop = &fio; 199 ips_stat_t ipsst; 200 ips_stat_t *ipsstp = &ipsst; 201 ipfrstat_t ifrst; 202 ipfrstat_t *ifrstp = &ifrst; 203 char *device = IPL_NAME, *memf = NULL; 204 char *options, *kern = NULL; 205 int c, myoptind; 206 207 int protocol = -1; /* -1 = wild card for any protocol */ 208 int refreshtime = 1; /* default update time */ 209 int sport = -1; /* -1 = wild card for any source port */ 210 int dport = -1; /* -1 = wild card for any dest port */ 211 int topclosed = 0; /* do not show closed tcp sessions */ 212 i6addr_t saddr, daddr; 213 u_32_t frf; 214 215 #ifdef USE_INET6 216 options = "6aACdfghIilnostvD:M:N:P:RS:T:"; 217 #else 218 options = "aACdfghIilnostvD:M:N:P:RS:T:"; 219 #endif 220 221 saddr.in4.s_addr = INADDR_ANY; /* default any v4 source addr */ 222 daddr.in4.s_addr = INADDR_ANY; /* default any v4 dest addr */ 223 #ifdef USE_INET6 224 saddr.in6 = in6addr_any; /* default any v6 source addr */ 225 daddr.in6 = in6addr_any; /* default any v6 dest addr */ 226 #endif 227 228 /* Don't warn about invalid flags when we run getopt for the 1st time */ 229 opterr = 0; 230 231 /* 232 * Parse these two arguments now lest there be any buffer overflows 233 * in the parsing of the rest. 234 */ 235 myoptind = optind; 236 while ((c = getopt(argc, argv, options)) != -1) { 237 switch (c) 238 { 239 case 'M' : 240 memf = optarg; 241 live_kernel = 0; 242 break; 243 case 'N' : 244 kern = optarg; 245 live_kernel = 0; 246 break; 247 } 248 } 249 optind = myoptind; 250 251 if (live_kernel == 1) { 252 if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) { 253 perror("open(IPSTATE_NAME)"); 254 exit(-1); 255 } 256 if ((ipf_fd = open(device, O_RDONLY)) == -1) { 257 fprintf(stderr, "open(%s)", device); 258 perror(""); 259 exit(-1); 260 } 261 } 262 263 if (kern != NULL || memf != NULL) { 264 (void)setgid(getgid()); 265 (void)setreuid(getuid(), getuid()); 266 if (openkmem(kern, memf) == -1) 267 exit(-1); 268 } 269 270 if (live_kernel == 1) 271 (void) checkrev(device); 272 (void)setgid(getgid()); 273 (void)setreuid(getuid(), getuid()); 274 275 opterr = 1; 276 277 while ((c = getopt(argc, argv, options)) != -1) 278 { 279 switch (c) 280 { 281 #ifdef USE_INET6 282 case '6' : 283 use_inet6 = 1; 284 break; 285 #endif 286 case 'a' : 287 opts |= OPT_ACCNT|OPT_SHOWLIST; 288 break; 289 case 'A' : 290 opts |= OPT_AUTHSTATS; 291 break; 292 case 'C' : 293 topclosed = 1; 294 break; 295 case 'd' : 296 opts |= OPT_DEBUG; 297 break; 298 case 'D' : 299 parse_ipportstr(optarg, &daddr, &dport); 300 break; 301 case 'f' : 302 opts |= OPT_FRSTATES; 303 break; 304 case 'g' : 305 opts |= OPT_GROUPS; 306 break; 307 case 'h' : 308 opts |= OPT_HITS; 309 break; 310 case 'i' : 311 opts |= OPT_INQUE|OPT_SHOWLIST; 312 break; 313 case 'I' : 314 opts |= OPT_INACTIVE; 315 break; 316 case 'l' : 317 opts |= OPT_SHOWLIST; 318 break; 319 case 'M' : 320 break; 321 case 'N' : 322 break; 323 case 'n' : 324 opts |= OPT_SHOWLINENO; 325 break; 326 case 'o' : 327 opts |= OPT_OUTQUE|OPT_SHOWLIST; 328 break; 329 case 'P' : 330 protocol = getproto(optarg); 331 if (protocol == -1) { 332 fprintf(stderr, "%s: Invalid protocol: %s\n", 333 argv[0], optarg); 334 exit(-2); 335 } 336 break; 337 case 'R' : 338 opts |= OPT_NORESOLVE; 339 break; 340 case 's' : 341 opts |= OPT_IPSTATES; 342 break; 343 case 'S' : 344 parse_ipportstr(optarg, &saddr, &sport); 345 break; 346 case 't' : 347 #ifdef STATETOP 348 opts |= OPT_STATETOP; 349 break; 350 #else 351 fprintf(stderr, 352 "%s: state top facility not compiled in\n", 353 argv[0]); 354 exit(-2); 355 #endif 356 case 'T' : 357 if (!sscanf(optarg, "%d", &refreshtime) || 358 (refreshtime <= 0)) { 359 fprintf(stderr, 360 "%s: Invalid refreshtime < 1 : %s\n", 361 argv[0], optarg); 362 exit(-2); 363 } 364 break; 365 case 'v' : 366 opts |= OPT_VERBOSE; 367 opts |= OPT_UNDEF; 368 break; 369 default : 370 usage(argv[0]); 371 break; 372 } 373 } 374 375 if (live_kernel == 1) { 376 bzero((char *)&fio, sizeof(fio)); 377 bzero((char *)&ipsst, sizeof(ipsst)); 378 bzero((char *)&ifrst, sizeof(ifrst)); 379 380 ipfstate_live(device, &fiop, &ipsstp, &ifrstp, 381 &frauthstp, &frf); 382 } else 383 ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); 384 385 if (opts & OPT_IPSTATES) { 386 showipstates(ipsstp); 387 } else if (opts & OPT_SHOWLIST) { 388 showlist(fiop); 389 if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){ 390 opts &= ~OPT_OUTQUE; 391 showlist(fiop); 392 } 393 } else if (opts & OPT_FRSTATES) 394 showfrstates(ifrstp); 395 #ifdef STATETOP 396 else if (opts & OPT_STATETOP) 397 topipstates(saddr, daddr, sport, dport, protocol, 398 use_inet6 ? 6 : 4, refreshtime, topclosed); 399 #endif 400 else if (opts & OPT_AUTHSTATS) 401 showauthstates(frauthstp); 402 else if (opts & OPT_GROUPS) 403 showgroups(fiop); 404 else 405 showstats(fiop, frf); 406 407 return 0; 408 } 409 410 411 /* 412 * Fill in the stats structures from the live kernel, using a combination 413 * of ioctl's and copying directly from kernel memory. 414 */ 415 static void ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) 416 char *device; 417 friostat_t **fiopp; 418 ips_stat_t **ipsstpp; 419 ipfrstat_t **ifrstpp; 420 fr_authstat_t **frauthstpp; 421 u_32_t *frfp; 422 { 423 ipfobj_t ipfo; 424 425 if (checkrev(device) == -1) { 426 fprintf(stderr, "User/kernel version check failed\n"); 427 exit(1); 428 } 429 430 if ((opts & OPT_AUTHSTATS) == 0) { 431 bzero((caddr_t)&ipfo, sizeof(ipfo)); 432 ipfo.ipfo_rev = IPFILTER_VERSION; 433 ipfo.ipfo_size = sizeof(friostat_t); 434 ipfo.ipfo_ptr = (void *)*fiopp; 435 ipfo.ipfo_type = IPFOBJ_IPFSTAT; 436 437 if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) { 438 perror("ioctl(ipf:SIOCGETFS)"); 439 exit(-1); 440 } 441 442 if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1) 443 perror("ioctl(SIOCGETFF)"); 444 } 445 446 if ((opts & OPT_IPSTATES) != 0) { 447 448 bzero((caddr_t)&ipfo, sizeof(ipfo)); 449 ipfo.ipfo_rev = IPFILTER_VERSION; 450 ipfo.ipfo_size = sizeof(ips_stat_t); 451 ipfo.ipfo_ptr = (void *)*ipsstpp; 452 ipfo.ipfo_type = IPFOBJ_STATESTAT; 453 454 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { 455 perror("ioctl(state:SIOCGETFS)"); 456 exit(-1); 457 } 458 if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) { 459 perror("ioctl(state:SIOCGETLG)"); 460 exit(-1); 461 } 462 } 463 464 if ((opts & OPT_FRSTATES) != 0) { 465 bzero((caddr_t)&ipfo, sizeof(ipfo)); 466 ipfo.ipfo_rev = IPFILTER_VERSION; 467 ipfo.ipfo_size = sizeof(ipfrstat_t); 468 ipfo.ipfo_ptr = (void *)*ifrstpp; 469 ipfo.ipfo_type = IPFOBJ_FRAGSTAT; 470 471 if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) { 472 perror("ioctl(SIOCGFRST)"); 473 exit(-1); 474 } 475 } 476 477 if (opts & OPT_VERBOSE) 478 PRINTF("opts %#x name %s\n", opts, device); 479 480 if ((opts & OPT_AUTHSTATS) != 0) { 481 if (ipf_fd >= 0) { 482 close(ipf_fd); 483 ipf_fd = -1; 484 } 485 device = IPAUTH_NAME; 486 if ((ipf_fd = open(device, O_RDONLY)) == -1) { 487 perror("open"); 488 exit(-1); 489 } 490 491 bzero((caddr_t)&ipfo, sizeof(ipfo)); 492 ipfo.ipfo_rev = IPFILTER_VERSION; 493 ipfo.ipfo_size = sizeof(fr_authstat_t); 494 ipfo.ipfo_ptr = (void *)*frauthstpp; 495 ipfo.ipfo_type = IPFOBJ_AUTHSTAT; 496 497 if (ioctl(ipf_fd, SIOCATHST, &ipfo) == -1) { 498 perror("ioctl(SIOCATHST)"); 499 exit(-1); 500 } 501 } 502 } 503 504 505 /* 506 * Build up the stats structures from data held in the "core" memory. 507 * This is mainly useful when looking at data in crash dumps and ioctl's 508 * just won't work any more. 509 */ 510 static void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) 511 char *kernel; 512 friostat_t **fiopp; 513 ips_stat_t **ipsstpp; 514 ipfrstat_t **ifrstpp; 515 fr_authstat_t **frauthstpp; 516 u_32_t *frfp; 517 { 518 static fr_authstat_t frauthst, *frauthstp; 519 static ips_stat_t ipsst, *ipsstp; 520 static ipfrstat_t ifrst, *ifrstp; 521 static friostat_t fio, *fiop; 522 int temp; 523 524 void *rules[2][2]; 525 struct nlist deadlist[43] = { 526 { "fr_authstats" }, /* 0 */ 527 { "fae_list" }, 528 { "ipauth" }, 529 { "fr_authlist" }, 530 { "fr_authstart" }, 531 { "fr_authend" }, /* 5 */ 532 { "fr_authnext" }, 533 { "fr_auth" }, 534 { "fr_authused" }, 535 { "fr_authsize" }, 536 { "fr_defaultauthage" }, /* 10 */ 537 { "fr_authpkts" }, 538 { "fr_auth_lock" }, 539 { "frstats" }, 540 { "ips_stats" }, 541 { "ips_num" }, /* 15 */ 542 { "ips_wild" }, 543 { "ips_list" }, 544 { "ips_table" }, 545 { "fr_statemax" }, 546 { "fr_statesize" }, /* 20 */ 547 { "fr_state_doflush" }, 548 { "fr_state_lock" }, 549 { "ipfr_heads" }, 550 { "ipfr_nattab" }, 551 { "ipfr_stats" }, /* 25 */ 552 { "ipfr_inuse" }, 553 { "fr_ipfrttl" }, 554 { "fr_frag_lock" }, 555 { "ipfr_timer_id" }, 556 { "fr_nat_lock" }, /* 30 */ 557 { "ipfilter" }, 558 { "ipfilter6" }, 559 { "ipacct" }, 560 { "ipacct6" }, 561 { "ipl_frouteok" }, /* 35 */ 562 { "fr_running" }, 563 { "ipfgroups" }, 564 { "fr_active" }, 565 { "fr_pass" }, 566 { "fr_flags" }, /* 40 */ 567 { "ipstate_logging" }, 568 { NULL } 569 }; 570 571 572 frauthstp = &frauthst; 573 ipsstp = &ipsst; 574 ifrstp = &ifrst; 575 fiop = &fio; 576 577 *frfp = 0; 578 *fiopp = fiop; 579 *ipsstpp = ipsstp; 580 *ifrstpp = ifrstp; 581 *frauthstpp = frauthstp; 582 583 bzero((char *)fiop, sizeof(*fiop)); 584 bzero((char *)ipsstp, sizeof(*ipsstp)); 585 bzero((char *)ifrstp, sizeof(*ifrstp)); 586 bzero((char *)frauthstp, sizeof(*frauthstp)); 587 588 if (nlist(kernel, deadlist) == -1) { 589 fprintf(stderr, "nlist error\n"); 590 return; 591 } 592 593 /* 594 * This is for SIOCGETFF. 595 */ 596 kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp)); 597 598 /* 599 * f_locks is a combination of the lock variable from each part of 600 * ipfilter (state, auth, nat, fragments). 601 */ 602 kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop)); 603 kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value, 604 sizeof(fiop->f_locks[0])); 605 kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value, 606 sizeof(fiop->f_locks[1])); 607 kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value, 608 sizeof(fiop->f_locks[2])); 609 kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value, 610 sizeof(fiop->f_locks[3])); 611 612 /* 613 * Get pointers to each list of rules (active, inactive, in, out) 614 */ 615 kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules)); 616 fiop->f_fin[0] = rules[0][0]; 617 fiop->f_fin[1] = rules[0][1]; 618 fiop->f_fout[0] = rules[1][0]; 619 fiop->f_fout[1] = rules[1][1]; 620 621 /* 622 * Same for IPv6, except make them null if support for it is not 623 * being compiled in. 624 */ 625 #ifdef USE_INET6 626 kmemcpy((char *)&rules, (u_long)deadlist[32].n_value, sizeof(rules)); 627 fiop->f_fin6[0] = rules[0][0]; 628 fiop->f_fin6[1] = rules[0][1]; 629 fiop->f_fout6[0] = rules[1][0]; 630 fiop->f_fout6[1] = rules[1][1]; 631 #else 632 fiop->f_fin6[0] = NULL; 633 fiop->f_fin6[1] = NULL; 634 fiop->f_fout6[0] = NULL; 635 fiop->f_fout6[1] = NULL; 636 #endif 637 638 /* 639 * Now get accounting rules pointers. 640 */ 641 kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules)); 642 fiop->f_acctin[0] = rules[0][0]; 643 fiop->f_acctin[1] = rules[0][1]; 644 fiop->f_acctout[0] = rules[1][0]; 645 fiop->f_acctout[1] = rules[1][1]; 646 647 #ifdef USE_INET6 648 kmemcpy((char *)&rules, (u_long)deadlist[34].n_value, sizeof(rules)); 649 fiop->f_acctin6[0] = rules[0][0]; 650 fiop->f_acctin6[1] = rules[0][1]; 651 fiop->f_acctout6[0] = rules[1][0]; 652 fiop->f_acctout6[1] = rules[1][1]; 653 #else 654 fiop->f_acctin6[0] = NULL; 655 fiop->f_acctin6[1] = NULL; 656 fiop->f_acctout6[0] = NULL; 657 fiop->f_acctout6[1] = NULL; 658 #endif 659 660 /* 661 * A collection of "global" variables used inside the kernel which 662 * are all collected in friostat_t via ioctl. 663 */ 664 kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[35].n_value, 665 sizeof(fiop->f_froute)); 666 kmemcpy((char *)&fiop->f_running, (u_long)deadlist[36].n_value, 667 sizeof(fiop->f_running)); 668 kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[37].n_value, 669 sizeof(fiop->f_groups)); 670 kmemcpy((char *)&fiop->f_active, (u_long)deadlist[38].n_value, 671 sizeof(fiop->f_active)); 672 kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[39].n_value, 673 sizeof(fiop->f_defpass)); 674 675 /* 676 * Build up the state information stats structure. 677 */ 678 kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp)); 679 kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp)); 680 ipsstp->iss_active = temp; 681 ipsstp->iss_table = (void *)deadlist[18].n_value; 682 ipsstp->iss_list = (void *)deadlist[17].n_value; 683 684 /* 685 * Build up the authentiation information stats structure. 686 */ 687 kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value, 688 sizeof(*frauthstp)); 689 frauthstp->fas_faelist = (void *)deadlist[1].n_value; 690 691 /* 692 * Build up the fragment information stats structure. 693 */ 694 kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value, 695 sizeof(*ifrstp)); 696 ifrstp->ifs_table = (void *)deadlist[23].n_value; 697 ifrstp->ifs_nattab = (void *)deadlist[24].n_value; 698 kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value, 699 sizeof(ifrstp->ifs_inuse)); 700 701 /* 702 * Get logging on/off switches 703 */ 704 kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value, 705 sizeof(state_logging)); 706 } 707 708 709 /* 710 * Display the kernel stats for packets blocked and passed and other 711 * associated running totals which are kept. 712 */ 713 static void showstats(fp, frf) 714 struct friostat *fp; 715 u_32_t frf; 716 { 717 718 PRINTF("bad packets:\t\tin %lu\tout %lu\n", 719 fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); 720 #ifdef USE_INET6 721 PRINTF(" IPv6 packets:\t\tin %lu out %lu\n", 722 fp->f_st[0].fr_ipv6, fp->f_st[1].fr_ipv6); 723 #endif 724 PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu", 725 fp->f_st[0].fr_block, fp->f_st[0].fr_pass, 726 fp->f_st[0].fr_nom); 727 PRINTF(" counted %lu short %lu\n", 728 fp->f_st[0].fr_acct, fp->f_st[0].fr_short); 729 PRINTF("output packets:\t\tblocked %lu passed %lu nomatch %lu", 730 fp->f_st[1].fr_block, fp->f_st[1].fr_pass, 731 fp->f_st[1].fr_nom); 732 PRINTF(" counted %lu short %lu\n", 733 fp->f_st[1].fr_acct, fp->f_st[1].fr_short); 734 PRINTF(" input packets logged:\tblocked %lu passed %lu\n", 735 fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); 736 PRINTF("output packets logged:\tblocked %lu passed %lu\n", 737 fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); 738 PRINTF(" packets logged:\tinput %lu output %lu\n", 739 fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl); 740 PRINTF(" log failures:\t\tinput %lu output %lu\n", 741 fp->f_st[0].fr_skip, fp->f_st[1].fr_skip); 742 PRINTF("fragment state(in):\tkept %lu\tlost %lu\tnot fragmented %lu\n", 743 fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr, 744 fp->f_st[0].fr_cfr); 745 PRINTF("fragment state(out):\tkept %lu\tlost %lu\tnot fragmented %lu\n", 746 fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr, 747 fp->f_st[0].fr_cfr); 748 PRINTF("packet state(in):\tkept %lu\tlost %lu\n", 749 fp->f_st[0].fr_ads, fp->f_st[0].fr_bads); 750 PRINTF("packet state(out):\tkept %lu\tlost %lu\n", 751 fp->f_st[1].fr_ads, fp->f_st[1].fr_bads); 752 PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n", 753 fp->f_st[0].fr_ret, fp->f_st[1].fr_ret); 754 PRINTF("Invalid source(in):\t%lu\n", fp->f_st[0].fr_badsrc); 755 PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n", 756 fp->f_st[0].fr_chit, fp->f_st[1].fr_chit); 757 PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n", 758 fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]); 759 PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n", 760 fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]); 761 PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n", 762 fp->f_froute[0], fp->f_froute[1]); 763 PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n", 764 fp->f_st[0].fr_tcpbad, fp->f_st[1].fr_tcpbad); 765 PRINTF("IPF Ticks:\t%lu\n", fp->f_ticks); 766 767 PRINTF("Packet log flags set: (%#x)\n", frf); 768 if (frf & FF_LOGPASS) 769 PRINTF("\tpackets passed through filter\n"); 770 if (frf & FF_LOGBLOCK) 771 PRINTF("\tpackets blocked by filter\n"); 772 if (frf & FF_LOGNOMATCH) 773 PRINTF("\tpackets not matched by filter\n"); 774 if (!frf) 775 PRINTF("\tnone\n"); 776 } 777 778 779 /* 780 * Print out a list of rules from the kernel, starting at the one passed. 781 */ 782 static void printlivelist(out, set, fp, group, comment) 783 int out, set; 784 frentry_t *fp; 785 char *group, *comment; 786 { 787 frgroup_t *grtop, *grtail, *g; 788 struct frentry fb, *fg; 789 int n; 790 ipfruleiter_t rule; 791 ipfobj_t obj; 792 793 fb.fr_next = fp; 794 n = 0; 795 796 grtop = NULL; 797 grtail = NULL; 798 rule.iri_ver = use_inet6? AF_INET6 : AF_INET; 799 rule.iri_inout = out; 800 rule.iri_active = set; 801 rule.iri_rule = &fb; 802 if (group != NULL) 803 strncpy(rule.iri_group, group, FR_GROUPLEN); 804 else 805 rule.iri_group[0] = '\0'; 806 807 bzero((char *)&obj, sizeof(obj)); 808 obj.ipfo_rev = IPFILTER_VERSION; 809 obj.ipfo_type = IPFOBJ_IPFITER; 810 obj.ipfo_size = sizeof(rule); 811 obj.ipfo_ptr = &rule; 812 813 do { 814 u_long array[1000]; 815 816 memset(array, 0xff, sizeof(array)); 817 fp = (frentry_t *)array; 818 rule.iri_rule = fp; 819 if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) { 820 perror("ioctl(SIOCIPFITER)"); 821 return; 822 } 823 if (fp->fr_data != NULL) 824 fp->fr_data = (char *)fp + sizeof(*fp); 825 826 n++; 827 828 if (opts & (OPT_HITS|OPT_VERBOSE)) 829 #ifdef USE_QUAD_T 830 PRINTF("%qu ", (unsigned long long) fp->fr_hits); 831 #else 832 PRINTF("%lu ", fp->fr_hits); 833 #endif 834 if (opts & (OPT_ACCNT|OPT_VERBOSE)) 835 #ifdef USE_QUAD_T 836 PRINTF("%qu ", (unsigned long long) fp->fr_bytes); 837 #else 838 PRINTF("%lu ", fp->fr_bytes); 839 #endif 840 if (opts & OPT_SHOWLINENO) 841 PRINTF("@%d ", n); 842 843 printfr(fp, ioctl); 844 if (opts & OPT_DEBUG) { 845 binprint(fp, sizeof(*fp)); 846 if (fp->fr_data != NULL && fp->fr_dsize > 0) 847 binprint(fp->fr_data, fp->fr_dsize); 848 } 849 850 if (fp->fr_grhead[0] != '\0') { 851 g = calloc(1, sizeof(*g)); 852 853 if (g != NULL) { 854 strncpy(g->fg_name, fp->fr_grhead, 855 FR_GROUPLEN); 856 if (grtop == NULL) { 857 grtop = g; 858 grtail = g; 859 } else { 860 grtail->fg_next = g; 861 grtail = g; 862 } 863 } 864 } 865 } while (fp->fr_next != NULL); 866 867 while ((g = grtop) != NULL) { 868 printlivelist(out, set, NULL, g->fg_name, comment); 869 grtop = g->fg_next; 870 free(g); 871 } 872 } 873 874 875 static void printdeadlist(out, set, fp, group, comment) 876 int out, set; 877 frentry_t *fp; 878 char *group, *comment; 879 { 880 frgroup_t *grtop, *grtail, *g; 881 struct frentry fb, *fg; 882 char *data; 883 u_32_t type; 884 int n; 885 886 fb.fr_next = fp; 887 n = 0; 888 grtop = NULL; 889 grtail = NULL; 890 891 do { 892 fp = fb.fr_next; 893 if (kmemcpy((char *)&fb, (u_long)fb.fr_next, 894 sizeof(fb)) == -1) { 895 perror("kmemcpy"); 896 return; 897 } 898 899 data = NULL; 900 type = fb.fr_type & ~FR_T_BUILTIN; 901 if (type == FR_T_IPF || type == FR_T_BPFOPC) { 902 if (fb.fr_dsize) { 903 data = malloc(fb.fr_dsize); 904 905 if (kmemcpy(data, (u_long)fb.fr_data, 906 fb.fr_dsize) == -1) { 907 perror("kmemcpy"); 908 return; 909 } 910 fb.fr_data = data; 911 } 912 } 913 914 n++; 915 916 if (opts & (OPT_HITS|OPT_VERBOSE)) 917 #ifdef USE_QUAD_T 918 PRINTF("%qu ", (unsigned long long) fb.fr_hits); 919 #else 920 PRINTF("%lu ", fb.fr_hits); 921 #endif 922 if (opts & (OPT_ACCNT|OPT_VERBOSE)) 923 #ifdef USE_QUAD_T 924 PRINTF("%qu ", (unsigned long long) fb.fr_bytes); 925 #else 926 PRINTF("%lu ", fb.fr_bytes); 927 #endif 928 if (opts & OPT_SHOWLINENO) 929 PRINTF("@%d ", n); 930 931 printfr(fp, ioctl); 932 if (opts & OPT_DEBUG) { 933 binprint(fp, sizeof(*fp)); 934 if (fb.fr_data != NULL && fb.fr_dsize > 0) 935 binprint(fb.fr_data, fb.fr_dsize); 936 } 937 if (data != NULL) 938 free(data); 939 if (fb.fr_grhead[0] != '\0') { 940 g = calloc(1, sizeof(*g)); 941 942 if (g != NULL) { 943 strncpy(g->fg_name, fb.fr_grhead, 944 FR_GROUPLEN); 945 if (grtop == NULL) { 946 grtop = g; 947 grtail = g; 948 } else { 949 grtail->fg_next = g; 950 grtail = g; 951 } 952 } 953 } 954 if (type == FR_T_CALLFUNC) { 955 printdeadlist(out, set, fb.fr_data, group, 956 "# callfunc: "); 957 } 958 } while (fb.fr_next != NULL); 959 960 while ((g = grtop) != NULL) { 961 printdeadlist(out, set, NULL, g->fg_name, comment); 962 grtop = g->fg_next; 963 free(g); 964 } 965 } 966 967 968 /* 969 * print out all of the asked for rule sets, using the stats struct as 970 * the base from which to get the pointers. 971 */ 972 static void showlist(fiop) 973 struct friostat *fiop; 974 { 975 struct frentry *fp = NULL; 976 int i, set; 977 978 set = fiop->f_active; 979 if (opts & OPT_INACTIVE) 980 set = 1 - set; 981 if (opts & OPT_ACCNT) { 982 #ifdef USE_INET6 983 if ((use_inet6) && (opts & OPT_OUTQUE)) { 984 i = F_ACOUT; 985 fp = (struct frentry *)fiop->f_acctout6[set]; 986 } else if ((use_inet6) && (opts & OPT_INQUE)) { 987 i = F_ACIN; 988 fp = (struct frentry *)fiop->f_acctin6[set]; 989 } else 990 #endif 991 if (opts & OPT_OUTQUE) { 992 i = F_ACOUT; 993 fp = (struct frentry *)fiop->f_acctout[set]; 994 } else if (opts & OPT_INQUE) { 995 i = F_ACIN; 996 fp = (struct frentry *)fiop->f_acctin[set]; 997 } else { 998 FPRINTF(stderr, "No -i or -o given with -a\n"); 999 return; 1000 } 1001 } else { 1002 #ifdef USE_INET6 1003 if ((use_inet6) && (opts & OPT_OUTQUE)) { 1004 i = F_OUT; 1005 fp = (struct frentry *)fiop->f_fout6[set]; 1006 } else if ((use_inet6) && (opts & OPT_INQUE)) { 1007 i = F_IN; 1008 fp = (struct frentry *)fiop->f_fin6[set]; 1009 } else 1010 #endif 1011 if (opts & OPT_OUTQUE) { 1012 i = F_OUT; 1013 fp = (struct frentry *)fiop->f_fout[set]; 1014 } else if (opts & OPT_INQUE) { 1015 i = F_IN; 1016 fp = (struct frentry *)fiop->f_fin[set]; 1017 } else 1018 return; 1019 } 1020 if (opts & OPT_VERBOSE) 1021 FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i); 1022 1023 if (opts & OPT_VERBOSE) 1024 PRINTF("fp %p set %d\n", fp, set); 1025 if (!fp) { 1026 FPRINTF(stderr, "empty list for %s%s\n", 1027 (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]); 1028 return; 1029 } 1030 if (live_kernel == 1) 1031 printlivelist(i, set, fp, NULL, NULL); 1032 else 1033 printdeadlist(i, set, fp, NULL, NULL); 1034 } 1035 1036 1037 /* 1038 * Display ipfilter stateful filtering information 1039 */ 1040 static void showipstates(ipsp) 1041 ips_stat_t *ipsp; 1042 { 1043 u_long minlen, maxlen, totallen, *buckets; 1044 int i, sz; 1045 1046 sz = sizeof(*buckets) * ipsp->iss_statesize; 1047 buckets = (u_long *)malloc(sz); 1048 if (buckets == NULL) { 1049 perror("malloc"); 1050 exit(1); 1051 } 1052 if (kmemcpy((char *)buckets, (u_long)ipsp->iss_bucketlen, sz)) { 1053 free(buckets); 1054 return; 1055 } 1056 1057 /* 1058 * If a list of states hasn't been asked for, only print out stats 1059 */ 1060 if (!(opts & OPT_SHOWLIST)) { 1061 PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n", 1062 ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp); 1063 PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits, 1064 ipsp->iss_miss); 1065 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu max bucket\n", 1066 ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_bucketfull); 1067 PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu bkts in use\n", 1068 ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse); 1069 PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n", 1070 ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin); 1071 1072 PRINTF("State logging %sabled\n", 1073 state_logging ? "en" : "dis"); 1074 1075 PRINTF("\nState table bucket statistics:\n"); 1076 PRINTF("\t%lu in use\t\n", ipsp->iss_inuse); 1077 1078 minlen = ipsp->iss_max; 1079 totallen = 0; 1080 maxlen = 0; 1081 1082 for (i = 0; i < ipsp->iss_statesize; i++) { 1083 if (buckets[i] > maxlen) 1084 maxlen = buckets[i]; 1085 if (buckets[i] < minlen) 1086 minlen = buckets[i]; 1087 totallen += buckets[i]; 1088 } 1089 1090 PRINTF("\t%2.2f%% bucket usage\n\t%lu minimal length\n", 1091 ((float)ipsp->iss_inuse / ipsp->iss_statesize) * 100.0, 1092 minlen); 1093 PRINTF("\t%lu maximal length\n\t%.3f average length\n", 1094 maxlen, 1095 ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse : 1096 0.0); 1097 1098 #define ENTRIES_PER_LINE 5 1099 1100 if (opts & OPT_VERBOSE) { 1101 PRINTF("\nCurrent bucket sizes :\n"); 1102 for (i = 0; i < ipsp->iss_statesize; i++) { 1103 if ((i % ENTRIES_PER_LINE) == 0) 1104 PRINTF("\t"); 1105 PRINTF("%4d -> %4lu", i, buckets[i]); 1106 if ((i % ENTRIES_PER_LINE) == 1107 (ENTRIES_PER_LINE - 1)) 1108 PRINTF("\n"); 1109 else 1110 PRINTF(" "); 1111 } 1112 PRINTF("\n"); 1113 } 1114 PRINTF("\n"); 1115 1116 free(buckets); 1117 return; 1118 } 1119 1120 /* 1121 * Print out all the state information currently held in the kernel. 1122 */ 1123 while (ipsp->iss_list != NULL) { 1124 ipsp->iss_list = printstate(ipsp->iss_list, opts, 1125 ipsp->iss_ticks); 1126 } 1127 1128 free(buckets); 1129 } 1130 1131 1132 #ifdef STATETOP 1133 static int handle_resize = 0, handle_break = 0; 1134 1135 static void topipstates(saddr, daddr, sport, dport, protocol, ver, 1136 refreshtime, topclosed) 1137 i6addr_t saddr; 1138 i6addr_t daddr; 1139 int sport; 1140 int dport; 1141 int protocol; 1142 int ver; 1143 int refreshtime; 1144 int topclosed; 1145 { 1146 char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE]; 1147 int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT; 1148 int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0; 1149 int len, srclen, dstlen, forward = 1, c = 0; 1150 ips_stat_t ipsst, *ipsstp = &ipsst; 1151 statetop_t *tstable = NULL, *tp; 1152 const char *errstr = ""; 1153 ipstate_t ips; 1154 ipfobj_t ipfo; 1155 struct timeval selecttimeout; 1156 char hostnm[HOSTNMLEN]; 1157 struct protoent *proto; 1158 fd_set readfd; 1159 time_t t; 1160 1161 /* install signal handlers */ 1162 signal(SIGINT, sig_break); 1163 signal(SIGQUIT, sig_break); 1164 signal(SIGTERM, sig_break); 1165 signal(SIGWINCH, sig_resize); 1166 1167 /* init ncurses stuff */ 1168 initscr(); 1169 cbreak(); 1170 noecho(); 1171 curs_set(0); 1172 timeout(0); 1173 getmaxyx(stdscr, maxy, maxx); 1174 1175 /* init hostname */ 1176 gethostname(hostnm, sizeof(hostnm) - 1); 1177 hostnm[sizeof(hostnm) - 1] = '\0'; 1178 1179 /* init ipfobj_t stuff */ 1180 bzero((caddr_t)&ipfo, sizeof(ipfo)); 1181 ipfo.ipfo_rev = IPFILTER_VERSION; 1182 ipfo.ipfo_size = sizeof(*ipsstp); 1183 ipfo.ipfo_ptr = (void *)ipsstp; 1184 ipfo.ipfo_type = IPFOBJ_STATESTAT; 1185 1186 /* repeat until user aborts */ 1187 while ( 1 ) { 1188 1189 /* get state table */ 1190 bzero((char *)&ipsst, sizeof(ipsst)); 1191 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { 1192 errstr = "ioctl(SIOCGETFS)"; 1193 ret = -1; 1194 goto out; 1195 } 1196 1197 /* clear the history */ 1198 tsentry = -1; 1199 1200 /* reset max str len */ 1201 srclen = dstlen = 0; 1202 1203 /* read the state table and store in tstable */ 1204 for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) { 1205 1206 if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list, 1207 sizeof(ips))) 1208 break; 1209 1210 if (ips.is_v != ver) 1211 continue; 1212 1213 /* check v4 src/dest addresses */ 1214 if (ips.is_v == 4) { 1215 if ((saddr.in4.s_addr != INADDR_ANY && 1216 saddr.in4.s_addr != ips.is_saddr) || 1217 (daddr.in4.s_addr != INADDR_ANY && 1218 daddr.in4.s_addr != ips.is_daddr)) 1219 continue; 1220 } 1221 #ifdef USE_INET6 1222 /* check v6 src/dest addresses */ 1223 if (ips.is_v == 6) { 1224 if ((IP6_NEQ(&saddr, &in6addr_any) && 1225 IP6_NEQ(&saddr, &ips.is_src)) || 1226 (IP6_NEQ(&daddr, &in6addr_any) && 1227 IP6_NEQ(&daddr, &ips.is_dst))) 1228 continue; 1229 } 1230 #endif 1231 /* check protocol */ 1232 if (protocol > 0 && protocol != ips.is_p) 1233 continue; 1234 1235 /* check ports if protocol is TCP or UDP */ 1236 if (((ips.is_p == IPPROTO_TCP) || 1237 (ips.is_p == IPPROTO_UDP)) && 1238 (((sport > 0) && (htons(sport) != ips.is_sport)) || 1239 ((dport > 0) && (htons(dport) != ips.is_dport)))) 1240 continue; 1241 1242 /* show closed TCP sessions ? */ 1243 if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) && 1244 (ips.is_state[0] >= IPF_TCPS_LAST_ACK) && 1245 (ips.is_state[1] >= IPF_TCPS_LAST_ACK)) 1246 continue; 1247 1248 /* 1249 * if necessary make room for this state 1250 * entry 1251 */ 1252 tsentry++; 1253 if (!maxtsentries || tsentry == maxtsentries) { 1254 maxtsentries += STGROWSIZE; 1255 tstable = realloc(tstable, 1256 maxtsentries * sizeof(statetop_t)); 1257 if (tstable == NULL) { 1258 perror("realloc"); 1259 exit(-1); 1260 } 1261 } 1262 1263 /* get max src/dest address string length */ 1264 len = strlen(getip(ips.is_v, &ips.is_src)); 1265 if (srclen < len) 1266 srclen = len; 1267 len = strlen(getip(ips.is_v, &ips.is_dst)); 1268 if (dstlen < len) 1269 dstlen = len; 1270 1271 /* fill structure */ 1272 tp = tstable + tsentry; 1273 tp->st_src = ips.is_src; 1274 tp->st_dst = ips.is_dst; 1275 tp->st_p = ips.is_p; 1276 tp->st_v = ips.is_v; 1277 tp->st_state[0] = ips.is_state[0]; 1278 tp->st_state[1] = ips.is_state[1]; 1279 if (forward) { 1280 tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1]; 1281 tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1]; 1282 } else { 1283 tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3]; 1284 tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3]; 1285 } 1286 tp->st_age = ips.is_die - ipsstp->iss_ticks; 1287 if ((ips.is_p == IPPROTO_TCP) || 1288 (ips.is_p == IPPROTO_UDP)) { 1289 tp->st_sport = ips.is_sport; 1290 tp->st_dport = ips.is_dport; 1291 } 1292 } 1293 1294 1295 /* sort the array */ 1296 if (tsentry != -1) { 1297 switch (sorting) 1298 { 1299 case STSORT_PR: 1300 qsort(tstable, tsentry + 1, 1301 sizeof(statetop_t), sort_p); 1302 break; 1303 case STSORT_PKTS: 1304 qsort(tstable, tsentry + 1, 1305 sizeof(statetop_t), sort_pkts); 1306 break; 1307 case STSORT_BYTES: 1308 qsort(tstable, tsentry + 1, 1309 sizeof(statetop_t), sort_bytes); 1310 break; 1311 case STSORT_TTL: 1312 qsort(tstable, tsentry + 1, 1313 sizeof(statetop_t), sort_ttl); 1314 break; 1315 case STSORT_SRCIP: 1316 qsort(tstable, tsentry + 1, 1317 sizeof(statetop_t), sort_srcip); 1318 break; 1319 case STSORT_SRCPT: 1320 qsort(tstable, tsentry +1, 1321 sizeof(statetop_t), sort_srcpt); 1322 break; 1323 case STSORT_DSTIP: 1324 qsort(tstable, tsentry + 1, 1325 sizeof(statetop_t), sort_dstip); 1326 break; 1327 case STSORT_DSTPT: 1328 qsort(tstable, tsentry + 1, 1329 sizeof(statetop_t), sort_dstpt); 1330 break; 1331 default: 1332 break; 1333 } 1334 } 1335 1336 /* handle window resizes */ 1337 if (handle_resize) { 1338 endwin(); 1339 initscr(); 1340 cbreak(); 1341 noecho(); 1342 curs_set(0); 1343 timeout(0); 1344 getmaxyx(stdscr, maxy, maxx); 1345 redraw = 1; 1346 handle_resize = 0; 1347 } 1348 1349 /* stop program? */ 1350 if (handle_break) 1351 break; 1352 1353 /* print title */ 1354 erase(); 1355 attron(A_BOLD); 1356 winy = 0; 1357 move(winy,0); 1358 sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION); 1359 for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++) 1360 printw(" "); 1361 printw("%s", str1); 1362 attroff(A_BOLD); 1363 1364 /* just for fun add a clock */ 1365 move(winy, maxx - 8); 1366 t = time(NULL); 1367 strftime(str1, 80, "%T", localtime(&t)); 1368 printw("%s\n", str1); 1369 1370 /* 1371 * print the display filters, this is placed in the loop, 1372 * because someday I might add code for changing these 1373 * while the programming is running :-) 1374 */ 1375 if (sport >= 0) 1376 sprintf(str1, "%s,%d", getip(ver, &saddr), sport); 1377 else 1378 sprintf(str1, "%s", getip(ver, &saddr)); 1379 1380 if (dport >= 0) 1381 sprintf(str2, "%s,%d", getip(ver, &daddr), dport); 1382 else 1383 sprintf(str2, "%s", getip(ver, &daddr)); 1384 1385 if (protocol < 0) 1386 strcpy(str3, "any"); 1387 else if ((proto = getprotobynumber(protocol)) != NULL) 1388 sprintf(str3, "%s", proto->p_name); 1389 else 1390 sprintf(str3, "%d", protocol); 1391 1392 switch (sorting) 1393 { 1394 case STSORT_PR: 1395 sprintf(str4, "proto"); 1396 break; 1397 case STSORT_PKTS: 1398 sprintf(str4, "# pkts"); 1399 break; 1400 case STSORT_BYTES: 1401 sprintf(str4, "# bytes"); 1402 break; 1403 case STSORT_TTL: 1404 sprintf(str4, "ttl"); 1405 break; 1406 case STSORT_SRCIP: 1407 sprintf(str4, "src ip"); 1408 break; 1409 case STSORT_SRCPT: 1410 sprintf(str4, "src port"); 1411 break; 1412 case STSORT_DSTIP: 1413 sprintf(str4, "dest ip"); 1414 break; 1415 case STSORT_DSTPT: 1416 sprintf(str4, "dest port"); 1417 break; 1418 default: 1419 sprintf(str4, "unknown"); 1420 break; 1421 } 1422 1423 if (reverse) 1424 strcat(str4, " (reverse)"); 1425 1426 winy += 2; 1427 move(winy,0); 1428 printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n", 1429 str1, str2, str3, str4); 1430 1431 /* 1432 * For an IPv4 IP address we need at most 15 characters, 1433 * 4 tuples of 3 digits, separated by 3 dots. Enforce this 1434 * length, so the colums do not change positions based 1435 * on the size of the IP address. This length makes the 1436 * output fit in a 80 column terminal. 1437 * We are lacking a good solution for IPv6 addresses (that 1438 * can be longer that 15 characters), so we do not enforce 1439 * a maximum on the IP field size. 1440 */ 1441 if (srclen < 15) 1442 srclen = 15; 1443 if (dstlen < 15) 1444 dstlen = 15; 1445 1446 /* print column description */ 1447 winy += 2; 1448 move(winy,0); 1449 attron(A_BOLD); 1450 printw("%-*s %-*s %3s %4s %7s %9s %9s\n", 1451 srclen + 6, "Source IP", dstlen + 6, "Destination IP", 1452 "ST", "PR", "#pkts", "#bytes", "ttl"); 1453 attroff(A_BOLD); 1454 1455 /* print all the entries */ 1456 tp = tstable; 1457 if (reverse) 1458 tp += tsentry; 1459 1460 if (tsentry > maxy - 6) 1461 tsentry = maxy - 6; 1462 for (i = 0; i <= tsentry; i++) { 1463 /* print src/dest and port */ 1464 if ((tp->st_p == IPPROTO_TCP) || 1465 (tp->st_p == IPPROTO_UDP)) { 1466 sprintf(str1, "%s,%hu", 1467 getip(tp->st_v, &tp->st_src), 1468 ntohs(tp->st_sport)); 1469 sprintf(str2, "%s,%hu", 1470 getip(tp->st_v, &tp->st_dst), 1471 ntohs(tp->st_dport)); 1472 } else { 1473 sprintf(str1, "%s", getip(tp->st_v, 1474 &tp->st_src)); 1475 sprintf(str2, "%s", getip(tp->st_v, 1476 &tp->st_dst)); 1477 } 1478 winy++; 1479 move(winy, 0); 1480 printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2); 1481 1482 /* print state */ 1483 sprintf(str1, "%X/%X", tp->st_state[0], 1484 tp->st_state[1]); 1485 printw(" %3s", str1); 1486 1487 /* print protocol */ 1488 proto = getprotobynumber(tp->st_p); 1489 if (proto) { 1490 strncpy(str1, proto->p_name, 4); 1491 str1[4] = '\0'; 1492 } else { 1493 sprintf(str1, "%d", tp->st_p); 1494 } 1495 /* just print icmp for IPv6-ICMP */ 1496 if (tp->st_p == IPPROTO_ICMPV6) 1497 strcpy(str1, "icmp"); 1498 printw(" %4s", str1); 1499 1500 /* print #pkt/#bytes */ 1501 #ifdef USE_QUAD_T 1502 printw(" %7qu %9qu", (unsigned long long) tp->st_pkts, 1503 (unsigned long long) tp->st_bytes); 1504 #else 1505 printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes); 1506 #endif 1507 printw(" %9s", ttl_to_string(tp->st_age)); 1508 1509 if (reverse) 1510 tp--; 1511 else 1512 tp++; 1513 } 1514 1515 /* screen data structure is filled, now update the screen */ 1516 if (redraw) 1517 clearok(stdscr,1); 1518 1519 if (refresh() == ERR) 1520 break; 1521 if (redraw) { 1522 clearok(stdscr,0); 1523 redraw = 0; 1524 } 1525 1526 /* wait for key press or a 1 second time out period */ 1527 selecttimeout.tv_sec = refreshtime; 1528 selecttimeout.tv_usec = 0; 1529 FD_ZERO(&readfd); 1530 FD_SET(0, &readfd); 1531 select(1, &readfd, NULL, NULL, &selecttimeout); 1532 1533 /* if key pressed, read all waiting keys */ 1534 if (FD_ISSET(0, &readfd)) { 1535 c = wgetch(stdscr); 1536 if (c == ERR) 1537 continue; 1538 1539 if (ISALPHA(c) && ISUPPER(c)) 1540 c = TOLOWER(c); 1541 if (c == 'l') { 1542 redraw = 1; 1543 } else if (c == 'q') { 1544 break; 1545 } else if (c == 'r') { 1546 reverse = !reverse; 1547 } else if (c == 'b') { 1548 forward = 0; 1549 } else if (c == 'f') { 1550 forward = 1; 1551 } else if (c == 's') { 1552 if (++sorting > STSORT_MAX) 1553 sorting = 0; 1554 } 1555 } 1556 } /* while */ 1557 1558 out: 1559 printw("\n"); 1560 curs_set(1); 1561 nocbreak(); 1562 endwin(); 1563 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