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