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