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