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 defined(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 u_long array[1000]; 819 820 fb.fr_next = fp; 821 n = 0; 822 823 grtop = NULL; 824 grtail = NULL; 825 rule.iri_ver = use_inet6? AF_INET6 : AF_INET; 826 rule.iri_inout = out; 827 rule.iri_active = set; 828 rule.iri_nrules = 1; 829 rule.iri_rule = &fb; 830 if (group != NULL) 831 strncpy(rule.iri_group, group, FR_GROUPLEN); 832 else 833 rule.iri_group[0] = '\0'; 834 835 bzero((char *)&obj, sizeof(obj)); 836 obj.ipfo_rev = IPFILTER_VERSION; 837 obj.ipfo_type = IPFOBJ_IPFITER; 838 obj.ipfo_size = sizeof(rule); 839 obj.ipfo_ptr = &rule; 840 841 do { 842 memset(array, 0xff, sizeof(array)); 843 fp = (frentry_t *)array; 844 rule.iri_rule = fp; 845 if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) { 846 perror("ioctl(SIOCIPFITER)"); 847 return; 848 } 849 if (fp->fr_data != NULL) 850 fp->fr_data = (char *)fp + sizeof(*fp); 851 852 n++; 853 854 if (opts & (OPT_HITS|OPT_VERBOSE)) 855 #ifdef USE_QUAD_T 856 PRINTF("%qu ", (unsigned long long) fp->fr_hits); 857 #else 858 PRINTF("%lu ", fp->fr_hits); 859 #endif 860 if (opts & (OPT_ACCNT|OPT_VERBOSE)) 861 #ifdef USE_QUAD_T 862 PRINTF("%qu ", (unsigned long long) fp->fr_bytes); 863 #else 864 PRINTF("%lu ", fp->fr_bytes); 865 #endif 866 if (opts & OPT_SHOWLINENO) 867 PRINTF("@%d ", n); 868 869 printfr(fp, ioctl); 870 if (opts & OPT_DEBUG) { 871 binprint(fp, sizeof(*fp)); 872 if (fp->fr_data != NULL && fp->fr_dsize > 0) 873 binprint(fp->fr_data, fp->fr_dsize); 874 } 875 876 if (fp->fr_grhead[0] != '\0') { 877 g = calloc(1, sizeof(*g)); 878 879 if (g != NULL) { 880 strncpy(g->fg_name, fp->fr_grhead, 881 FR_GROUPLEN); 882 if (grtop == NULL) { 883 grtop = g; 884 grtail = g; 885 } else { 886 grtail->fg_next = g; 887 grtail = g; 888 } 889 } 890 } 891 } while (fp->fr_next != NULL); 892 893 while ((g = grtop) != NULL) { 894 printlivelist(out, set, NULL, g->fg_name, comment); 895 grtop = g->fg_next; 896 free(g); 897 } 898 } 899 900 901 static void printdeadlist(out, set, fp, group, comment) 902 int out, set; 903 frentry_t *fp; 904 char *group, *comment; 905 { 906 frgroup_t *grtop, *grtail, *g; 907 struct frentry fb, *fg; 908 char *data; 909 u_32_t type; 910 int n; 911 912 fb.fr_next = fp; 913 n = 0; 914 grtop = NULL; 915 grtail = NULL; 916 917 do { 918 fp = fb.fr_next; 919 if (kmemcpy((char *)&fb, (u_long)fb.fr_next, 920 sizeof(fb)) == -1) { 921 perror("kmemcpy"); 922 return; 923 } 924 925 data = NULL; 926 type = fb.fr_type & ~FR_T_BUILTIN; 927 if (type == FR_T_IPF || type == FR_T_BPFOPC) { 928 if (fb.fr_dsize) { 929 data = malloc(fb.fr_dsize); 930 931 if (kmemcpy(data, (u_long)fb.fr_data, 932 fb.fr_dsize) == -1) { 933 perror("kmemcpy"); 934 return; 935 } 936 fb.fr_data = data; 937 } 938 } 939 940 n++; 941 942 if (opts & (OPT_HITS|OPT_VERBOSE)) 943 #ifdef USE_QUAD_T 944 PRINTF("%qu ", (unsigned long long) fb.fr_hits); 945 #else 946 PRINTF("%lu ", fb.fr_hits); 947 #endif 948 if (opts & (OPT_ACCNT|OPT_VERBOSE)) 949 #ifdef USE_QUAD_T 950 PRINTF("%qu ", (unsigned long long) fb.fr_bytes); 951 #else 952 PRINTF("%lu ", fb.fr_bytes); 953 #endif 954 if (opts & OPT_SHOWLINENO) 955 PRINTF("@%d ", n); 956 957 printfr(fp, ioctl); 958 if (opts & OPT_DEBUG) { 959 binprint(fp, sizeof(*fp)); 960 if (fb.fr_data != NULL && fb.fr_dsize > 0) 961 binprint(fb.fr_data, fb.fr_dsize); 962 } 963 if (data != NULL) 964 free(data); 965 if (fb.fr_grhead[0] != '\0') { 966 g = calloc(1, sizeof(*g)); 967 968 if (g != NULL) { 969 strncpy(g->fg_name, fb.fr_grhead, 970 FR_GROUPLEN); 971 if (grtop == NULL) { 972 grtop = g; 973 grtail = g; 974 } else { 975 grtail->fg_next = g; 976 grtail = g; 977 } 978 } 979 } 980 if (type == FR_T_CALLFUNC) { 981 printdeadlist(out, set, fb.fr_data, group, 982 "# callfunc: "); 983 } 984 } while (fb.fr_next != NULL); 985 986 while ((g = grtop) != NULL) { 987 printdeadlist(out, set, NULL, g->fg_name, comment); 988 grtop = g->fg_next; 989 free(g); 990 } 991 } 992 993 994 /* 995 * print out all of the asked for rule sets, using the stats struct as 996 * the base from which to get the pointers. 997 */ 998 static void showlist(fiop) 999 struct friostat *fiop; 1000 { 1001 struct frentry *fp = NULL; 1002 int i, set; 1003 1004 set = fiop->f_active; 1005 if (opts & OPT_INACTIVE) 1006 set = 1 - set; 1007 if (opts & OPT_ACCNT) { 1008 #ifdef USE_INET6 1009 if ((use_inet6) && (opts & OPT_OUTQUE)) { 1010 i = F_ACOUT; 1011 fp = (struct frentry *)fiop->f_acctout6[set]; 1012 } else if ((use_inet6) && (opts & OPT_INQUE)) { 1013 i = F_ACIN; 1014 fp = (struct frentry *)fiop->f_acctin6[set]; 1015 } else 1016 #endif 1017 if (opts & OPT_OUTQUE) { 1018 i = F_ACOUT; 1019 fp = (struct frentry *)fiop->f_acctout[set]; 1020 } else if (opts & OPT_INQUE) { 1021 i = F_ACIN; 1022 fp = (struct frentry *)fiop->f_acctin[set]; 1023 } else { 1024 FPRINTF(stderr, "No -i or -o given with -a\n"); 1025 return; 1026 } 1027 } else { 1028 #ifdef USE_INET6 1029 if ((use_inet6) && (opts & OPT_OUTQUE)) { 1030 i = F_OUT; 1031 fp = (struct frentry *)fiop->f_fout6[set]; 1032 } else if ((use_inet6) && (opts & OPT_INQUE)) { 1033 i = F_IN; 1034 fp = (struct frentry *)fiop->f_fin6[set]; 1035 } else 1036 #endif 1037 if (opts & OPT_OUTQUE) { 1038 i = F_OUT; 1039 fp = (struct frentry *)fiop->f_fout[set]; 1040 } else if (opts & OPT_INQUE) { 1041 i = F_IN; 1042 fp = (struct frentry *)fiop->f_fin[set]; 1043 } else 1044 return; 1045 } 1046 if (opts & OPT_VERBOSE) 1047 FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i); 1048 1049 if (opts & OPT_VERBOSE) 1050 PRINTF("fp %p set %d\n", fp, set); 1051 if (!fp) { 1052 FPRINTF(stderr, "empty list for %s%s\n", 1053 (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]); 1054 return; 1055 } 1056 if (live_kernel == 1) 1057 printlivelist(i, set, fp, NULL, NULL); 1058 else 1059 printdeadlist(i, set, fp, NULL, NULL); 1060 } 1061 1062 1063 /* 1064 * Display ipfilter stateful filtering information 1065 */ 1066 static void showipstates(ipsp) 1067 ips_stat_t *ipsp; 1068 { 1069 u_long minlen, maxlen, totallen, *buckets; 1070 int i, sz; 1071 1072 sz = sizeof(*buckets) * ipsp->iss_statesize; 1073 buckets = (u_long *)malloc(sz); 1074 if (buckets == NULL) { 1075 perror("malloc"); 1076 exit(1); 1077 } 1078 if (kmemcpy((char *)buckets, (u_long)ipsp->iss_bucketlen, sz)) { 1079 free(buckets); 1080 return; 1081 } 1082 1083 /* 1084 * If a list of states hasn't been asked for, only print out stats 1085 */ 1086 if (!(opts & OPT_SHOWLIST)) { 1087 PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n", 1088 ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp); 1089 PRINTF("\t%lu hits\n\t%lu misses\n", 1090 ipsp->iss_hits, ipsp->iss_miss); 1091 PRINTF("\t%lu maximum\n\t%lu no memory\n", ipsp->iss_max, 1092 ipsp->iss_nomem); 1093 PRINTF("\t%lu active\n\t%lu expired\n", 1094 ipsp->iss_active, ipsp->iss_expire); 1095 PRINTF("\t%lu closed\n\t%u orphans\n", 1096 ipsp->iss_fin, ipsp->iss_orphans); 1097 1098 PRINTF("State logging %sabled\n", 1099 state_logging ? "en" : "dis"); 1100 1101 PRINTF("\nState table bucket statistics:\n"); 1102 PRINTF("\t%lu in use\n\t%lu max bucket\n", ipsp->iss_inuse, 1103 ipsp->iss_bucketfull); 1104 1105 minlen = ipsp->iss_max; 1106 totallen = 0; 1107 maxlen = 0; 1108 1109 for (i = 0; i < ipsp->iss_statesize; i++) { 1110 if (buckets[i] > maxlen) 1111 maxlen = buckets[i]; 1112 if (buckets[i] < minlen) 1113 minlen = buckets[i]; 1114 totallen += buckets[i]; 1115 } 1116 1117 PRINTF("\t%2.2f%% bucket usage\n\t%lu minimal length\n", 1118 ((float)ipsp->iss_inuse / ipsp->iss_statesize) * 100.0, 1119 minlen); 1120 PRINTF("\t%lu maximal length\n\t%.3f average length\n", 1121 maxlen, 1122 ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse : 1123 0.0); 1124 1125 #define ENTRIES_PER_LINE 5 1126 1127 if (opts & OPT_VERBOSE) { 1128 PRINTF("\nCurrent bucket sizes :\n"); 1129 for (i = 0; i < ipsp->iss_statesize; i++) { 1130 if ((i % ENTRIES_PER_LINE) == 0) 1131 PRINTF("\t"); 1132 PRINTF("%4d -> %4lu", i, buckets[i]); 1133 if ((i % ENTRIES_PER_LINE) == 1134 (ENTRIES_PER_LINE - 1)) 1135 PRINTF("\n"); 1136 else 1137 PRINTF(" "); 1138 } 1139 PRINTF("\n"); 1140 } 1141 PRINTF("\n"); 1142 1143 free(buckets); 1144 return; 1145 } 1146 1147 /* 1148 * Print out all the state information currently held in the kernel. 1149 */ 1150 while (ipsp->iss_list != NULL) { 1151 ipsp->iss_list = printstate(ipsp->iss_list, opts, 1152 ipsp->iss_ticks); 1153 } 1154 1155 free(buckets); 1156 } 1157 1158 1159 #ifdef STATETOP 1160 static int handle_resize = 0, handle_break = 0; 1161 1162 static void topipstates(saddr, daddr, sport, dport, protocol, ver, 1163 refreshtime, topclosed) 1164 i6addr_t saddr; 1165 i6addr_t daddr; 1166 int sport; 1167 int dport; 1168 int protocol; 1169 int ver; 1170 int refreshtime; 1171 int topclosed; 1172 { 1173 char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE]; 1174 int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT; 1175 int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0; 1176 int len, srclen, dstlen, forward = 1, c = 0; 1177 ips_stat_t ipsst, *ipsstp = &ipsst; 1178 statetop_t *tstable = NULL, *tp; 1179 const char *errstr = ""; 1180 ipstate_t ips; 1181 ipfobj_t ipfo; 1182 struct timeval selecttimeout; 1183 char hostnm[HOSTNMLEN]; 1184 struct protoent *proto; 1185 fd_set readfd; 1186 time_t t; 1187 1188 /* install signal handlers */ 1189 signal(SIGINT, sig_break); 1190 signal(SIGQUIT, sig_break); 1191 signal(SIGTERM, sig_break); 1192 signal(SIGWINCH, sig_resize); 1193 1194 /* init ncurses stuff */ 1195 initscr(); 1196 cbreak(); 1197 noecho(); 1198 curs_set(0); 1199 timeout(0); 1200 getmaxyx(stdscr, maxy, maxx); 1201 1202 /* init hostname */ 1203 gethostname(hostnm, sizeof(hostnm) - 1); 1204 hostnm[sizeof(hostnm) - 1] = '\0'; 1205 1206 /* init ipfobj_t stuff */ 1207 bzero((caddr_t)&ipfo, sizeof(ipfo)); 1208 ipfo.ipfo_rev = IPFILTER_VERSION; 1209 ipfo.ipfo_size = sizeof(*ipsstp); 1210 ipfo.ipfo_ptr = (void *)ipsstp; 1211 ipfo.ipfo_type = IPFOBJ_STATESTAT; 1212 1213 /* repeat until user aborts */ 1214 while ( 1 ) { 1215 1216 /* get state table */ 1217 bzero((char *)&ipsst, sizeof(ipsst)); 1218 if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { 1219 errstr = "ioctl(SIOCGETFS)"; 1220 ret = -1; 1221 goto out; 1222 } 1223 1224 /* clear the history */ 1225 tsentry = -1; 1226 1227 /* reset max str len */ 1228 srclen = dstlen = 0; 1229 1230 /* read the state table and store in tstable */ 1231 for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) { 1232 1233 if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list, 1234 sizeof(ips))) 1235 break; 1236 1237 if (ips.is_v != ver) 1238 continue; 1239 1240 /* check v4 src/dest addresses */ 1241 if (ips.is_v == 4) { 1242 if ((saddr.in4.s_addr != INADDR_ANY && 1243 saddr.in4.s_addr != ips.is_saddr) || 1244 (daddr.in4.s_addr != INADDR_ANY && 1245 daddr.in4.s_addr != ips.is_daddr)) 1246 continue; 1247 } 1248 #ifdef USE_INET6 1249 /* check v6 src/dest addresses */ 1250 if (ips.is_v == 6) { 1251 if ((IP6_NEQ(&saddr, &in6addr_any) && 1252 IP6_NEQ(&saddr, &ips.is_src)) || 1253 (IP6_NEQ(&daddr, &in6addr_any) && 1254 IP6_NEQ(&daddr, &ips.is_dst))) 1255 continue; 1256 } 1257 #endif 1258 /* check protocol */ 1259 if (protocol > 0 && protocol != ips.is_p) 1260 continue; 1261 1262 /* check ports if protocol is TCP or UDP */ 1263 if (((ips.is_p == IPPROTO_TCP) || 1264 (ips.is_p == IPPROTO_UDP)) && 1265 (((sport > 0) && (htons(sport) != ips.is_sport)) || 1266 ((dport > 0) && (htons(dport) != ips.is_dport)))) 1267 continue; 1268 1269 /* show closed TCP sessions ? */ 1270 if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) && 1271 (ips.is_state[0] >= IPF_TCPS_LAST_ACK) && 1272 (ips.is_state[1] >= IPF_TCPS_LAST_ACK)) 1273 continue; 1274 1275 /* 1276 * if necessary make room for this state 1277 * entry 1278 */ 1279 tsentry++; 1280 if (!maxtsentries || tsentry == maxtsentries) { 1281 maxtsentries += STGROWSIZE; 1282 tstable = realloc(tstable, 1283 maxtsentries * sizeof(statetop_t)); 1284 if (tstable == NULL) { 1285 perror("realloc"); 1286 exit(-1); 1287 } 1288 } 1289 1290 /* get max src/dest address string length */ 1291 len = strlen(getip(ips.is_v, &ips.is_src)); 1292 if (srclen < len) 1293 srclen = len; 1294 len = strlen(getip(ips.is_v, &ips.is_dst)); 1295 if (dstlen < len) 1296 dstlen = len; 1297 1298 /* fill structure */ 1299 tp = tstable + tsentry; 1300 tp->st_src = ips.is_src; 1301 tp->st_dst = ips.is_dst; 1302 tp->st_p = ips.is_p; 1303 tp->st_v = ips.is_v; 1304 tp->st_state[0] = ips.is_state[0]; 1305 tp->st_state[1] = ips.is_state[1]; 1306 if (forward) { 1307 tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1]; 1308 tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1]; 1309 } else { 1310 tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3]; 1311 tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3]; 1312 } 1313 tp->st_age = ips.is_die - ipsstp->iss_ticks; 1314 if ((ips.is_p == IPPROTO_TCP) || 1315 (ips.is_p == IPPROTO_UDP)) { 1316 tp->st_sport = ips.is_sport; 1317 tp->st_dport = ips.is_dport; 1318 } 1319 } 1320 1321 1322 /* sort the array */ 1323 if (tsentry != -1) { 1324 switch (sorting) 1325 { 1326 case STSORT_PR: 1327 qsort(tstable, tsentry + 1, 1328 sizeof(statetop_t), sort_p); 1329 break; 1330 case STSORT_PKTS: 1331 qsort(tstable, tsentry + 1, 1332 sizeof(statetop_t), sort_pkts); 1333 break; 1334 case STSORT_BYTES: 1335 qsort(tstable, tsentry + 1, 1336 sizeof(statetop_t), sort_bytes); 1337 break; 1338 case STSORT_TTL: 1339 qsort(tstable, tsentry + 1, 1340 sizeof(statetop_t), sort_ttl); 1341 break; 1342 case STSORT_SRCIP: 1343 qsort(tstable, tsentry + 1, 1344 sizeof(statetop_t), sort_srcip); 1345 break; 1346 case STSORT_SRCPT: 1347 qsort(tstable, tsentry +1, 1348 sizeof(statetop_t), sort_srcpt); 1349 break; 1350 case STSORT_DSTIP: 1351 qsort(tstable, tsentry + 1, 1352 sizeof(statetop_t), sort_dstip); 1353 break; 1354 case STSORT_DSTPT: 1355 qsort(tstable, tsentry + 1, 1356 sizeof(statetop_t), sort_dstpt); 1357 break; 1358 default: 1359 break; 1360 } 1361 } 1362 1363 /* handle window resizes */ 1364 if (handle_resize) { 1365 endwin(); 1366 initscr(); 1367 cbreak(); 1368 noecho(); 1369 curs_set(0); 1370 timeout(0); 1371 getmaxyx(stdscr, maxy, maxx); 1372 redraw = 1; 1373 handle_resize = 0; 1374 } 1375 1376 /* stop program? */ 1377 if (handle_break) 1378 break; 1379 1380 /* print title */ 1381 erase(); 1382 attron(A_BOLD); 1383 winy = 0; 1384 move(winy,0); 1385 sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION); 1386 for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++) 1387 printw(" "); 1388 printw("%s", str1); 1389 attroff(A_BOLD); 1390 1391 /* just for fun add a clock */ 1392 move(winy, maxx - 8); 1393 t = time(NULL); 1394 strftime(str1, 80, "%T", localtime(&t)); 1395 printw("%s\n", str1); 1396 1397 /* 1398 * print the display filters, this is placed in the loop, 1399 * because someday I might add code for changing these 1400 * while the programming is running :-) 1401 */ 1402 if (sport >= 0) 1403 sprintf(str1, "%s,%d", getip(ver, &saddr), sport); 1404 else 1405 sprintf(str1, "%s", getip(ver, &saddr)); 1406 1407 if (dport >= 0) 1408 sprintf(str2, "%s,%d", getip(ver, &daddr), dport); 1409 else 1410 sprintf(str2, "%s", getip(ver, &daddr)); 1411 1412 if (protocol < 0) 1413 strcpy(str3, "any"); 1414 else if ((proto = getprotobynumber(protocol)) != NULL) 1415 sprintf(str3, "%s", proto->p_name); 1416 else 1417 sprintf(str3, "%d", protocol); 1418 1419 switch (sorting) 1420 { 1421 case STSORT_PR: 1422 sprintf(str4, "proto"); 1423 break; 1424 case STSORT_PKTS: 1425 sprintf(str4, "# pkts"); 1426 break; 1427 case STSORT_BYTES: 1428 sprintf(str4, "# bytes"); 1429 break; 1430 case STSORT_TTL: 1431 sprintf(str4, "ttl"); 1432 break; 1433 case STSORT_SRCIP: 1434 sprintf(str4, "src ip"); 1435 break; 1436 case STSORT_SRCPT: 1437 sprintf(str4, "src port"); 1438 break; 1439 case STSORT_DSTIP: 1440 sprintf(str4, "dest ip"); 1441 break; 1442 case STSORT_DSTPT: 1443 sprintf(str4, "dest port"); 1444 break; 1445 default: 1446 sprintf(str4, "unknown"); 1447 break; 1448 } 1449 1450 if (reverse) 1451 strcat(str4, " (reverse)"); 1452 1453 winy += 2; 1454 move(winy,0); 1455 printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n", 1456 str1, str2, str3, str4); 1457 1458 /* 1459 * For an IPv4 IP address we need at most 15 characters, 1460 * 4 tuples of 3 digits, separated by 3 dots. Enforce this 1461 * length, so the colums do not change positions based 1462 * on the size of the IP address. This length makes the 1463 * output fit in a 80 column terminal. 1464 * We are lacking a good solution for IPv6 addresses (that 1465 * can be longer that 15 characters), so we do not enforce 1466 * a maximum on the IP field size. 1467 */ 1468 if (srclen < 15) 1469 srclen = 15; 1470 if (dstlen < 15) 1471 dstlen = 15; 1472 1473 /* print column description */ 1474 winy += 2; 1475 move(winy,0); 1476 attron(A_BOLD); 1477 printw("%-*s %-*s %3s %4s %7s %9s %9s\n", 1478 srclen + 6, "Source IP", dstlen + 6, "Destination IP", 1479 "ST", "PR", "#pkts", "#bytes", "ttl"); 1480 attroff(A_BOLD); 1481 1482 /* print all the entries */ 1483 tp = tstable; 1484 if (reverse) 1485 tp += tsentry; 1486 1487 if (tsentry > maxy - 6) 1488 tsentry = maxy - 6; 1489 for (i = 0; i <= tsentry; i++) { 1490 /* print src/dest and port */ 1491 if ((tp->st_p == IPPROTO_TCP) || 1492 (tp->st_p == IPPROTO_UDP)) { 1493 sprintf(str1, "%s,%hu", 1494 getip(tp->st_v, &tp->st_src), 1495 ntohs(tp->st_sport)); 1496 sprintf(str2, "%s,%hu", 1497 getip(tp->st_v, &tp->st_dst), 1498 ntohs(tp->st_dport)); 1499 } else { 1500 sprintf(str1, "%s", getip(tp->st_v, 1501 &tp->st_src)); 1502 sprintf(str2, "%s", getip(tp->st_v, 1503 &tp->st_dst)); 1504 } 1505 winy++; 1506 move(winy, 0); 1507 printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2); 1508 1509 /* print state */ 1510 sprintf(str1, "%X/%X", tp->st_state[0], 1511 tp->st_state[1]); 1512 printw(" %3s", str1); 1513 1514 /* print protocol */ 1515 proto = getprotobynumber(tp->st_p); 1516 if (proto) { 1517 strncpy(str1, proto->p_name, 4); 1518 str1[4] = '\0'; 1519 } else { 1520 sprintf(str1, "%d", tp->st_p); 1521 } 1522 /* just print icmp for IPv6-ICMP */ 1523 if (tp->st_p == IPPROTO_ICMPV6) 1524 strcpy(str1, "icmp"); 1525 printw(" %4s", str1); 1526 1527 /* print #pkt/#bytes */ 1528 #ifdef USE_QUAD_T 1529 printw(" %7qu %9qu", (unsigned long long) tp->st_pkts, 1530 (unsigned long long) tp->st_bytes); 1531 #else 1532 printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes); 1533 #endif 1534 printw(" %9s", ttl_to_string(tp->st_age)); 1535 1536 if (reverse) 1537 tp--; 1538 else 1539 tp++; 1540 } 1541 1542 /* screen data structure is filled, now update the screen */ 1543 if (redraw) 1544 clearok(stdscr,1); 1545 1546 if (refresh() == ERR) 1547 break; 1548 if (redraw) { 1549 clearok(stdscr,0); 1550 redraw = 0; 1551 } 1552 1553 /* wait for key press or a 1 second time out period */ 1554 selecttimeout.tv_sec = refreshtime; 1555 selecttimeout.tv_usec = 0; 1556 FD_ZERO(&readfd); 1557 FD_SET(0, &readfd); 1558 select(1, &readfd, NULL, NULL, &selecttimeout); 1559 1560 /* if key pressed, read all waiting keys */ 1561 if (FD_ISSET(0, &readfd)) { 1562 c = wgetch(stdscr); 1563 if (c == ERR) 1564 continue; 1565 1566 if (ISALPHA(c) && ISUPPER(c)) 1567 c = TOLOWER(c); 1568 if (c == 'l') { 1569 redraw = 1; 1570 } else if (c == 'q') { 1571 break; 1572 } else if (c == 'r') { 1573 reverse = !reverse; 1574 } else if (c == 'b') { 1575 forward = 0; 1576 } else if (c == 'f') { 1577 forward = 1; 1578 } else if (c == 's') { 1579 if (++sorting > STSORT_MAX) 1580 sorting = 0; 1581 } 1582 } 1583 } /* while */ 1584 1585 out: 1586 printw("\n"); 1587 refresh(); 1588 endwin(); 1589 free(tstable); 1590 if (ret != 0) 1591 perror(errstr); 1592 } 1593 #endif 1594 1595 1596 /* 1597 * Show fragment cache information that's held in the kernel. 1598 */ 1599 static void showfrstates(ifsp, ticks) 1600 ipfrstat_t *ifsp; 1601 u_long ticks; 1602 { 1603 struct ipfr *ipfrtab[IPFT_SIZE], ifr; 1604 int i; 1605 1606 /* 1607 * print out the numeric statistics 1608 */ 1609 PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n", 1610 ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits); 1611 PRINTF("\t%lu retrans\n\t%lu too short\n", 1612 ifsp->ifs_retrans0, ifsp->ifs_short); 1613 PRINTF("\t%lu no memory\n\t%lu already exist\n", 1614 ifsp->ifs_nomem, ifsp->ifs_exists); 1615 PRINTF("\t%lu inuse\n", ifsp->ifs_inuse); 1616 if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab))) 1617 return; 1618 1619 /* 1620 * Print out the contents (if any) of the fragment cache table. 1621 */ 1622 PRINTF("\n"); 1623 for (i = 0; i < IPFT_SIZE; i++) 1624 while (ipfrtab[i] != NULL) { 1625 if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], 1626 sizeof(ifr)) == -1) 1627 break; 1628 ifr.ipfr_ttl -= ticks; 1629 printfraginfo("", &ifr); 1630 ipfrtab[i] = ifr.ipfr_next; 1631 } 1632 /* 1633 * Print out the contents (if any) of the NAT fragment cache table. 1634 */ 1635 if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,sizeof(ipfrtab))) 1636 return; 1637 for (i = 0; i < IPFT_SIZE; i++) 1638 while (ipfrtab[i] != NULL) { 1639 if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], 1640 sizeof(ifr)) == -1) 1641 break; 1642 ifr.ipfr_ttl -= ticks; 1643 printfraginfo("NAT: ", &ifr); 1644 ipfrtab[i] = ifr.ipfr_next; 1645 } 1646 } 1647 1648 1649 /* 1650 * Show stats on how auth within IPFilter has been used 1651 */ 1652 static void showauthstates(asp) 1653 fr_authstat_t *asp; 1654 { 1655 frauthent_t *frap, fra; 1656 1657 #ifdef USE_QUAD_T 1658 printf("Authorisation hits: %qu\tmisses %qu\n", 1659 (unsigned long long) asp->fas_hits, 1660 (unsigned long long) asp->fas_miss); 1661 #else 1662 printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits, 1663 asp->fas_miss); 1664 #endif 1665 printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n", 1666 asp->fas_nospace, asp->fas_added, asp->fas_sendfail, 1667 asp->fas_sendok); 1668 printf("queok %ld\nquefail %ld\nexpire %ld\n", 1669 asp->fas_queok, asp->fas_quefail, asp->fas_expire); 1670 1671 frap = asp->fas_faelist; 1672 while (frap) { 1673 if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1) 1674 break; 1675 1676 printf("age %ld\t", fra.fae_age); 1677 printfr(&fra.fae_fr, ioctl); 1678 frap = fra.fae_next; 1679 } 1680 } 1681 1682 1683 /* 1684 * Display groups used for each of filter rules, accounting rules and 1685 * authentication, separately. 1686 */ 1687 static void showgroups(fiop) 1688 struct friostat *fiop; 1689 { 1690 static char *gnames[3] = { "Filter", "Accounting", "Authentication" }; 1691 static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH }; 1692 frgroup_t *fp, grp; 1693 int on, off, i; 1694 1695 on = fiop->f_active; 1696 off = 1 - on; 1697 1698 for (i = 0; i < 3; i++) { 1699 printf("%s groups (active):\n", gnames[i]); 1700 for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL; 1701 fp = grp.fg_next) 1702 if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) 1703 break; 1704 else 1705 printf("%s\n", grp.fg_name); 1706 printf("%s groups (inactive):\n", gnames[i]); 1707 for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL; 1708 fp = grp.fg_next) 1709 if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) 1710 break; 1711 else 1712 printf("%s\n", grp.fg_name); 1713 } 1714 } 1715 1716 static void parse_ipportstr(argument, ip, port) 1717 const char *argument; 1718 i6addr_t *ip; 1719 int *port; 1720 { 1721 char *s, *comma; 1722 int ok = 0; 1723 1724 /* make working copy of argument, Theoretically you must be able 1725 * to write to optarg, but that seems very ugly to me.... 1726 */ 1727 s = strdup(argument); 1728 if (s == NULL) 1729 return; 1730 1731 /* get port */ 1732 if ((comma = strchr(s, ',')) != NULL) { 1733 if (!strcasecmp(comma + 1, "any")) { 1734 *port = -1; 1735 } else if (!sscanf(comma + 1, "%d", port) || 1736 (*port < 0) || (*port > 65535)) { 1737 fprintf(stderr, "Invalid port specfication in %s\n", 1738 argument); 1739 free(s); 1740 exit(-2); 1741 } 1742 *comma = '\0'; 1743 } 1744 1745 1746 /* get ip address */ 1747 if (!strcasecmp(s, "any")) { 1748 ip->in4.s_addr = INADDR_ANY; 1749 #ifdef USE_INET6 1750 ip->in6 = in6addr_any; 1751 } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) { 1752 ok = 1; 1753 #endif 1754 } else if (inet_aton(s, &ip->in4)) 1755 ok = 1; 1756 1757 if (ok == 0) { 1758 fprintf(stderr, "Invalid IP address: %s\n", s); 1759 free(s); 1760 exit(-2); 1761 } 1762 1763 /* free allocated memory */ 1764 free(s); 1765 } 1766 1767 1768 #ifdef STATETOP 1769 static void sig_resize(s) 1770 int s; 1771 { 1772 handle_resize = 1; 1773 } 1774 1775 static void sig_break(s) 1776 int s; 1777 { 1778 handle_break = 1; 1779 } 1780 1781 static char *getip(v, addr) 1782 int v; 1783 i6addr_t *addr; 1784 { 1785 #ifdef USE_INET6 1786 static char hostbuf[MAXHOSTNAMELEN+1]; 1787 #endif 1788 1789 if (v == 4) 1790 return inet_ntoa(addr->in4); 1791 1792 #ifdef USE_INET6 1793 (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1); 1794 hostbuf[MAXHOSTNAMELEN] = '\0'; 1795 return hostbuf; 1796 #else 1797 return "IPv6"; 1798 #endif 1799 } 1800 1801 1802 static char *ttl_to_string(ttl) 1803 long int ttl; 1804 { 1805 static char ttlbuf[STSTRSIZE]; 1806 int hours, minutes, seconds; 1807 1808 /* ttl is in half seconds */ 1809 ttl /= 2; 1810 1811 hours = ttl / 3600; 1812 ttl = ttl % 3600; 1813 minutes = ttl / 60; 1814 seconds = ttl % 60; 1815 1816 if (hours > 0) 1817 sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds); 1818 else 1819 sprintf(ttlbuf, "%2d:%02d", minutes, seconds); 1820 return ttlbuf; 1821 } 1822 1823 1824 static int sort_pkts(a, b) 1825 const void *a; 1826 const void *b; 1827 { 1828 1829 register const statetop_t *ap = a; 1830 register const statetop_t *bp = b; 1831 1832 if (ap->st_pkts == bp->st_pkts) 1833 return 0; 1834 else if (ap->st_pkts < bp->st_pkts) 1835 return 1; 1836 return -1; 1837 } 1838 1839 1840 static int sort_bytes(a, b) 1841 const void *a; 1842 const void *b; 1843 { 1844 register const statetop_t *ap = a; 1845 register const statetop_t *bp = b; 1846 1847 if (ap->st_bytes == bp->st_bytes) 1848 return 0; 1849 else if (ap->st_bytes < bp->st_bytes) 1850 return 1; 1851 return -1; 1852 } 1853 1854 1855 static int sort_p(a, b) 1856 const void *a; 1857 const void *b; 1858 { 1859 register const statetop_t *ap = a; 1860 register const statetop_t *bp = b; 1861 1862 if (ap->st_p == bp->st_p) 1863 return 0; 1864 else if (ap->st_p < bp->st_p) 1865 return 1; 1866 return -1; 1867 } 1868 1869 1870 static int sort_ttl(a, b) 1871 const void *a; 1872 const void *b; 1873 { 1874 register const statetop_t *ap = a; 1875 register const statetop_t *bp = b; 1876 1877 if (ap->st_age == bp->st_age) 1878 return 0; 1879 else if (ap->st_age < bp->st_age) 1880 return 1; 1881 return -1; 1882 } 1883 1884 static int sort_srcip(a, b) 1885 const void *a; 1886 const void *b; 1887 { 1888 register const statetop_t *ap = a; 1889 register const statetop_t *bp = b; 1890 1891 #ifdef USE_INET6 1892 if (use_inet6) { 1893 if (IP6_EQ(&ap->st_src, &bp->st_src)) 1894 return 0; 1895 else if (IP6_GT(&ap->st_src, &bp->st_src)) 1896 return 1; 1897 } else 1898 #endif 1899 { 1900 if (ntohl(ap->st_src.in4.s_addr) == 1901 ntohl(bp->st_src.in4.s_addr)) 1902 return 0; 1903 else if (ntohl(ap->st_src.in4.s_addr) > 1904 ntohl(bp->st_src.in4.s_addr)) 1905 return 1; 1906 } 1907 return -1; 1908 } 1909 1910 static int sort_srcpt(a, b) 1911 const void *a; 1912 const void *b; 1913 { 1914 register const statetop_t *ap = a; 1915 register const statetop_t *bp = b; 1916 1917 if (htons(ap->st_sport) == htons(bp->st_sport)) 1918 return 0; 1919 else if (htons(ap->st_sport) > htons(bp->st_sport)) 1920 return 1; 1921 return -1; 1922 } 1923 1924 static int sort_dstip(a, b) 1925 const void *a; 1926 const void *b; 1927 { 1928 register const statetop_t *ap = a; 1929 register const statetop_t *bp = b; 1930 1931 #ifdef USE_INET6 1932 if (use_inet6) { 1933 if (IP6_EQ(&ap->st_dst, &bp->st_dst)) 1934 return 0; 1935 else if (IP6_GT(&ap->st_dst, &bp->st_dst)) 1936 return 1; 1937 } else 1938 #endif 1939 { 1940 if (ntohl(ap->st_dst.in4.s_addr) == 1941 ntohl(bp->st_dst.in4.s_addr)) 1942 return 0; 1943 else if (ntohl(ap->st_dst.in4.s_addr) > 1944 ntohl(bp->st_dst.in4.s_addr)) 1945 return 1; 1946 } 1947 return -1; 1948 } 1949 1950 static int sort_dstpt(a, b) 1951 const void *a; 1952 const void *b; 1953 { 1954 register const statetop_t *ap = a; 1955 register const statetop_t *bp = b; 1956 1957 if (htons(ap->st_dport) == htons(bp->st_dport)) 1958 return 0; 1959 else if (htons(ap->st_dport) > htons(bp->st_dport)) 1960 return 1; 1961 return -1; 1962 } 1963 1964 #endif 1965