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