Annotation of embedaddon/trafshow/show_stat.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1998,2004 Rinet Corp., Novosibirsk, Russia
! 3: *
! 4: * Redistribution and use in source forms, with and without modification,
! 5: * are permitted provided that this entire comment appears intact.
! 6: *
! 7: * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
! 8: */
! 9:
! 10: #ifdef HAVE_CONFIG_H
! 11: #include <config.h>
! 12: #endif
! 13:
! 14: #include <sys/param.h>
! 15: #include <sys/types.h>
! 16: #include <sys/socket.h>
! 17: #include <netinet/in.h>
! 18: #include <arpa/inet.h>
! 19: #include <stdio.h>
! 20: #include <stdlib.h>
! 21: #include <string.h>
! 22:
! 23: #include "show_stat.h"
! 24: #include "trafshow.h"
! 25: #include "screen.h"
! 26: #include "selector.h"
! 27: #include "netstat.h"
! 28: #include "getkey.h"
! 29: #include "addrtoname.h"
! 30:
! 31: ShowStatMode show_stat_mode = Size;
! 32: static int find_backflow(NETSTAT **list, int items, NETSTAT *at);
! 33: static void sort_backflow(NETSTAT **list, int items);
! 34:
! 35: static void
! 36: scale_size(addr, prot, data, rate)
! 37: int *addr, *prot, *data, *rate;
! 38: {
! 39: *addr = line_factor * (double)SHOW_STAT_ADDR;
! 40: *prot = line_factor * (double)SHOW_STAT_PROT;
! 41: *data = line_factor * (double)SHOW_STAT_DATA;
! 42: *rate = line_factor * (double)SHOW_STAT_RATE;
! 43: }
! 44:
! 45: static int
! 46: compare_pkt_len(p1, p2)
! 47: register const NETSTAT **p1, **p2;
! 48: {
! 49: if ((*p1)->pkt_len > (*p2)->pkt_len) return -1;
! 50: if ((*p1)->pkt_len < (*p2)->pkt_len) return 1;
! 51: return 0;
! 52: }
! 53:
! 54: static int
! 55: compare_data_len(p1, p2)
! 56: register const NETSTAT **p1, **p2;
! 57: {
! 58: if ((*p1)->data_len > (*p2)->data_len) return -1;
! 59: if ((*p1)->data_len < (*p2)->data_len) return 1;
! 60: return 0;
! 61: }
! 62:
! 63: static int
! 64: compare_pkt_cnt(p1, p2)
! 65: register const NETSTAT **p1, **p2;
! 66: {
! 67: if ((*p1)->pkt_cnt > (*p2)->pkt_cnt) return -1;
! 68: if ((*p1)->pkt_cnt < (*p2)->pkt_cnt) return 1;
! 69: return 0;
! 70: }
! 71:
! 72: static int
! 73: find_backflow(list, items, at)
! 74: NETSTAT **list;
! 75: int items;
! 76: NETSTAT *at;
! 77: {
! 78: int i;
! 79:
! 80: /* sanity check */
! 81: if (!list || items < 1 || !at)
! 82: return -1;
! 83:
! 84: for (i = 0; i < items; i++) {
! 85: if (netstat_bidir(at, list[i]))
! 86: return i;
! 87: }
! 88: return -1;
! 89: }
! 90:
! 91: /* too bad implementation -- it take alot of CPU cycles like deadloop. XXX */
! 92: static void
! 93: sort_backflow(list, items)
! 94: NETSTAT **list;
! 95: int items;
! 96: {
! 97: int i = 0, at;
! 98: NETSTAT *ns;
! 99:
! 100: while (i < items-1) {
! 101: ns = list[i++];
! 102: if ((at = find_backflow(&list[i], items - i, ns)) < 0)
! 103: continue;
! 104: if (at) {
! 105: ns = list[i + at];
! 106: memmove(&list[i + 1], &list[i], at * sizeof(NETSTAT *));
! 107: list[i] = ns;
! 108: }
! 109: i++;
! 110: }
! 111: }
! 112:
! 113: /*
! 114: * Pretty print an Internet address (net address + port).
! 115: */
! 116: static char *
! 117: ip_print(ver, proto, addr, dst, size)
! 118: int ver;
! 119: int proto;
! 120: const struct ip_address *addr;
! 121: char *dst;
! 122: int size;
! 123: {
! 124: const char *cp = 0;
! 125: char buf[100];
! 126:
! 127: if (ver == 4 && addr->ip_addr.s_addr) {
! 128: /*cp = intoa(addr->ip_addr.s_addr);*/
! 129: cp = ipaddr_string(&addr->ip_addr);
! 130: }
! 131: #ifdef INET6
! 132: else if (ver == 6 && !IN6_IS_ADDR_UNSPECIFIED(&addr->ip6_addr)) {
! 133: /*cp = inet_ntop(AF_INET6, &addr->ip6_addr, buf, sizeof(buf));*/
! 134: cp = ip6addr_string(&addr->ip6_addr);
! 135: }
! 136: #endif
! 137:
! 138: if (cp) {
! 139: (void)strncpy(dst, cp, size);
! 140: dst[size-1] = '\0';
! 141: } else snprintf(dst, size, "IPv%d", ver);
! 142:
! 143: if (addr->ip_port) {
! 144: char pb[20];
! 145: int len;
! 146: switch (proto) {
! 147: case IPPROTO_TCP:
! 148: if (nflag) {
! 149: sprintf(pb, "%d", ntohs(addr->ip_port));
! 150: cp = pb;
! 151: } else cp = tcpport_string(ntohs(addr->ip_port));
! 152: break;
! 153: case IPPROTO_UDP:
! 154: if (nflag) {
! 155: sprintf(pb, "%d", ntohs(addr->ip_port));
! 156: cp = pb;
! 157: } else cp = udpport_string(ntohs(addr->ip_port));
! 158: break;
! 159: case IPPROTO_ICMP:
! 160: if (nflag) {
! 161: sprintf(pb, "%04x", addr->ip_port - 1);
! 162: cp = pb;
! 163: } else cp = icmp_string(addr->ip_port - 1);
! 164: break;
! 165: #ifdef INET6
! 166: case IPPROTO_ICMPV6:
! 167: if (nflag) {
! 168: sprintf(pb, "%04x", addr->ip_port - 1);
! 169: cp = pb;
! 170: } else cp = icmpv6_string(addr->ip_port - 1);
! 171: break;
! 172: #endif
! 173: default: /* nonsense, but be strong */
! 174: sprintf(pb, "%d", ntohs(addr->ip_port));
! 175: cp = pb;
! 176: }
! 177: buf[0] = ',';
! 178: (void)strncpy(&buf[1], cp, 10);
! 179: buf[11] = '\0';
! 180: len = strlen(buf);
! 181: if (strlen(dst) + len < size)
! 182: (void)strcat(dst, buf);
! 183: else (void)strcpy(&dst[size - len - 1], buf);
! 184: }
! 185: return dst;
! 186: }
! 187:
! 188: static char *
! 189: sap_print(addr, sap, dst, size)
! 190: const u_char *addr;
! 191: u_char sap;
! 192: char *dst;
! 193: int size;
! 194: {
! 195: char buf[20];
! 196: int len;
! 197:
! 198: (void)strncpy(dst, etheraddr_string(addr), size);
! 199: dst[size-1] = '\0';
! 200:
! 201: buf[0] = '/';
! 202: if (nflag)
! 203: sprintf(&buf[1], "sap-%02x", sap & 0xff);
! 204: else (void)strncpy(&buf[1], llcsap_string(sap), 10);
! 205: buf[11] = '\0';
! 206: len = strlen(buf);
! 207: if (strlen(dst) + len < size)
! 208: (void)strcat(dst, buf);
! 209: else (void)strcpy(&dst[size - len - 1], buf);
! 210: return dst;
! 211: }
! 212:
! 213: void
! 214: hdr2str(nh, src_buf, src_len, dst_buf, dst_len, proto_buf, proto_len)
! 215: const struct netstat_header *nh;
! 216: char *src_buf, *dst_buf, *proto_buf;
! 217: int src_len, dst_len, proto_len;
! 218: {
! 219: const NETSTAT *ns;
! 220:
! 221: if (src_buf) *src_buf = '\0';
! 222: if (dst_buf) *dst_buf = '\0';
! 223: if (proto_buf) *proto_buf = '\0';
! 224:
! 225: /* sanity check */
! 226: if (!nh) return;
! 227:
! 228: ns = (NETSTAT *)nh;
! 229:
! 230: if (ns->ip_ver) {
! 231: if (src_buf && src_len > 1) {
! 232: ip_print(ns->ip_ver, ns->ip_proto, &ns->ip_src_addr,
! 233: src_buf, src_len);
! 234: }
! 235: if (dst_buf && dst_len > 1) {
! 236: ip_print(ns->ip_ver, ns->ip_proto, &ns->ip_dst_addr,
! 237: dst_buf, dst_len);
! 238: }
! 239: if (proto_buf && proto_len > 1) {
! 240: if (nflag)
! 241: snprintf(proto_buf, proto_len, "%d", (int)ns->ip_proto);
! 242: else (void)strncpy(proto_buf, ipproto_string(ns->ip_proto),
! 243: proto_len);
! 244: proto_buf[proto_len-1] = '\0';
! 245: }
! 246: } else if (ntohs(ns->eth_type) > 1500) { /* Ethernet II (DIX) */
! 247: if (src_buf && src_len > 1) {
! 248: (void)strncpy(src_buf, etheraddr_string(ns->eth_src_addr),
! 249: src_len);
! 250: src_buf[src_len-1] = '\0';
! 251: }
! 252: if (dst_buf && dst_len > 1) {
! 253: (void)strncpy(dst_buf, etheraddr_string(ns->eth_dst_addr),
! 254: dst_len);
! 255: dst_buf[dst_len-1] = '\0';
! 256: }
! 257: if (proto_buf && proto_len > 1) {
! 258: if (nflag)
! 259: snprintf(proto_buf, proto_len, "%04x", ntohs(ns->eth_type));
! 260: else (void)strncpy(proto_buf, ethertype_string(ns->eth_type),
! 261: proto_len);
! 262: proto_buf[proto_len-1] = '\0';
! 263: }
! 264: } else if (ns->eth_ssap == ns->eth_dsap) {
! 265: if (src_buf && src_len > 1) {
! 266: (void)strncpy(src_buf, etheraddr_string(ns->eth_src_addr),
! 267: src_len);
! 268: src_buf[src_len-1] = '\0';
! 269: }
! 270: if (dst_buf && dst_len > 1) {
! 271: (void)strncpy(dst_buf, etheraddr_string(ns->eth_dst_addr),
! 272: dst_len);
! 273: dst_buf[dst_len-1] = '\0';
! 274: }
! 275: if (proto_buf && proto_len > 1) {
! 276: if (nflag)
! 277: snprintf(proto_buf, proto_len, "sap-%02x",
! 278: (int)(ns->eth_ssap & 0xff));
! 279: else (void)strncpy(proto_buf, llcsap_string(ns->eth_ssap),
! 280: proto_len);
! 281: proto_buf[proto_len-1] = '\0';
! 282: }
! 283: } else {
! 284: if (src_buf && src_len > 1) {
! 285: sap_print(ns->eth_src_addr, ns->eth_ssap,
! 286: src_buf, src_len);
! 287: }
! 288: if (dst_buf && dst_len > 1) {
! 289: sap_print(ns->eth_dst_addr, ns->eth_dsap,
! 290: dst_buf, dst_len);
! 291: }
! 292: if (proto_buf && proto_len > 1) {
! 293: (void)strncpy(proto_buf, "802.3", proto_len);
! 294: proto_buf[proto_len-1] = '\0';
! 295: }
! 296: }
! 297: }
! 298:
! 299: static int
! 300: show_stat_header(dst, size, ph)
! 301: char *dst;
! 302: int size;
! 303: const PCAP_HANDLER *ph;
! 304: {
! 305: int addr_sz, prot_sz, data_sz, rate_sz;
! 306: char src_buf[100], dst_buf[100];
! 307: const char *data_ptr, *rate_ptr;
! 308:
! 309: /* sanity check */
! 310: if (!dst || size < 1 || !ph)
! 311: return 0;
! 312:
! 313: scale_size(&addr_sz, &prot_sz, &data_sz, &rate_sz);
! 314:
! 315: (void)strcpy(src_buf, "Source");
! 316: (void)strcpy(dst_buf, "Destination");
! 317: if (ph->masklen >= 0) {
! 318: sprintf(src_buf + strlen(src_buf), "/%d", ph->masklen);
! 319: sprintf(dst_buf + strlen(dst_buf), "/%d", ph->masklen);
! 320: }
! 321:
! 322: data_ptr = rate_ptr = "?";
! 323: switch (show_stat_mode) {
! 324: case Size:
! 325: data_ptr = "Size";
! 326: rate_ptr = "CPS";
! 327: break;
! 328: case Data:
! 329: data_ptr = "Data";
! 330: rate_ptr = "CPS";
! 331: break;
! 332: case Packets:
! 333: data_ptr = "Packets";
! 334: rate_ptr = "PPS";
! 335: break;
! 336: }
! 337: snprintf(dst, size,
! 338: "%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s",
! 339: addr_sz, addr_sz, src_buf,
! 340: addr_sz, addr_sz, dst_buf,
! 341: prot_sz, prot_sz, "Protocol",
! 342: data_sz, data_sz, data_ptr,
! 343: rate_sz, rate_sz, rate_ptr);
! 344: return 0;
! 345: }
! 346:
! 347: static int
! 348: show_stat_line(dst, size, ns_list, idx)
! 349: char *dst;
! 350: int size;
! 351: const NETSTAT **ns_list;
! 352: int idx;
! 353: {
! 354: int addr_sz, prot_sz, data_sz, rate_sz;
! 355: const NETSTAT *ns;
! 356: char src_buf[100], dst_buf[100], proto_buf[20], data_buf[20], rate_buf[20];
! 357:
! 358: /* sanity check */
! 359: if (!dst || size < 1 || !ns_list)
! 360: return 0;
! 361:
! 362: ns = ns_list[idx];
! 363:
! 364: scale_size(&addr_sz, &prot_sz, &data_sz, &rate_sz);
! 365:
! 366: hdr2str(&ns->ns_hdr,
! 367: src_buf, MIN(sizeof(src_buf), addr_sz + 1),
! 368: dst_buf, MIN(sizeof(dst_buf), addr_sz + 1),
! 369: proto_buf, MIN(sizeof(proto_buf), prot_sz + 1));
! 370:
! 371: data_buf[0] = '\0';
! 372: rate_buf[0] = '\0';
! 373: switch (show_stat_mode) {
! 374: case Size:
! 375: if (ns->pkt_len >= 10000)
! 376: snprintf(data_buf, sizeof(data_buf), "%uK", ns->pkt_len / 1024);
! 377: else snprintf(data_buf, sizeof(data_buf), "%u", ns->pkt_len);
! 378:
! 379: if (ns->pkt_len_rate >= 10000)
! 380: snprintf(rate_buf, sizeof(rate_buf), "%uK", ns->pkt_len_rate / 1024);
! 381: else if (ns->pkt_len_rate > 0)
! 382: snprintf(rate_buf, sizeof(rate_buf), "%u", ns->pkt_len_rate);
! 383: break;
! 384: case Data:
! 385: if (ns->data_len >= 10000)
! 386: snprintf(data_buf, sizeof(data_buf), "%uK", ns->data_len / 1024);
! 387: else snprintf(data_buf, sizeof(data_buf), "%u", ns->data_len);
! 388:
! 389: if (ns->data_len_rate >= 10000)
! 390: snprintf(rate_buf, sizeof(rate_buf), "%uK", ns->data_len_rate / 1024);
! 391: else if (ns->data_len_rate > 0)
! 392: snprintf(rate_buf, sizeof(rate_buf), "%u", ns->data_len_rate);
! 393: break;
! 394: case Packets:
! 395: snprintf(data_buf, sizeof(data_buf), "%u", ns->pkt_cnt);
! 396:
! 397: if (ns->pkt_cnt_rate > 0)
! 398: snprintf(rate_buf, sizeof(rate_buf), "%u", ns->pkt_cnt_rate);
! 399: break;
! 400: }
! 401:
! 402: snprintf(dst, size,
! 403: "%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s",
! 404: addr_sz, addr_sz, src_buf,
! 405: addr_sz, addr_sz, dst_buf,
! 406: prot_sz, prot_sz, proto_buf,
! 407: data_sz, data_sz, data_buf,
! 408: rate_sz, rate_sz, rate_buf);
! 409:
! 410: return ns->attr;
! 411: }
! 412:
! 413: static int
! 414: show_stat_footer(dst, size, ph)
! 415: char *dst;
! 416: int size;
! 417: const PCAP_HANDLER *ph;
! 418: {
! 419: const PCAP_HANDLER *top;
! 420: int addr_sz, prot_sz, data_sz, rate_sz, depth;
! 421: u_int64_t total = 0, rate = 0;
! 422: char stat_buf[50], data_buf[20], rate_buf[20];
! 423:
! 424: /* sanity check */
! 425: if (!dst || size < 1 || !ph)
! 426: return 0;
! 427:
! 428: scale_size(&addr_sz, &prot_sz, &data_sz, &rate_sz);
! 429:
! 430: depth = 0;
! 431: for (top = ph->top; top; top = top->top) depth++;
! 432: if (depth) {
! 433: snprintf(stat_buf, sizeof(stat_buf), "%d Flows (depth %d)",
! 434: netstat_count(ph), depth);
! 435: } else {
! 436: snprintf(stat_buf, sizeof(stat_buf), "%d Flows",
! 437: netstat_count(ph));
! 438: }
! 439:
! 440: switch (show_stat_mode) {
! 441: case Size:
! 442: total = ph->pkt_len;
! 443: rate = ph->pkt_len_rate;
! 444: break;
! 445: case Data:
! 446: total = ph->data_len;
! 447: rate = ph->data_len_rate;
! 448: break;
! 449: case Packets:
! 450: total = ph->pkt_cnt;
! 451: rate = ph->pkt_cnt_rate;
! 452: break;
! 453: }
! 454:
! 455: if (total >= 10000000)
! 456: snprintf(data_buf, sizeof(data_buf), "%uM",
! 457: (unsigned int)(total / (1024 * 1024)));
! 458: else if (total >= 10000)
! 459: snprintf(data_buf, sizeof(data_buf), "%uK",
! 460: (unsigned int)(total / 1024));
! 461: else snprintf(data_buf, sizeof(data_buf), "%u",
! 462: (unsigned int)total);
! 463:
! 464: if (rate >= 10000000)
! 465: snprintf(rate_buf, sizeof(rate_buf), "%uM",
! 466: (unsigned int)(rate / (1024 * 1024)));
! 467: else if (rate >= 10000)
! 468: snprintf(rate_buf, sizeof(rate_buf), "%uK",
! 469: (unsigned int)(rate / 1024));
! 470: else snprintf(rate_buf, sizeof(rate_buf), "%u",
! 471: (unsigned int)rate);
! 472:
! 473: snprintf(dst, size,
! 474: "%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s",
! 475: addr_sz, addr_sz, ph->name,
! 476: addr_sz, addr_sz, stat_buf,
! 477: prot_sz, prot_sz, "Total:",
! 478: data_sz, data_sz, data_buf,
! 479: rate_sz, rate_sz, rate_buf);
! 480: return 0;
! 481: }
! 482:
! 483: int
! 484: show_stat_input(ph, ch)
! 485: PCAP_HANDLER *ph;
! 486: int ch;
! 487: {
! 488: switch (ch) {
! 489: case '[': /* rotate list mode left */
! 490: case K_LEFT:
! 491: if (show_stat_mode == Size)
! 492: show_stat_mode = Packets;
! 493: else show_stat_mode--;
! 494: return 1;
! 495: case ']': /* rotate list mode right */
! 496: case K_RIGHT:
! 497: if (show_stat_mode == Packets)
! 498: show_stat_mode = Size;
! 499: else show_stat_mode++;
! 500: return 1;
! 501: case K_CTRL('R'): /* reset current netstat hash */
! 502: if (ph) {
! 503: netstat_purge(ph, 0);
! 504: show_stat_list(ph);
! 505: return 1;
! 506: }
! 507: break;
! 508: case K_TAB: /* follow to backflow */
! 509: if (ph) {
! 510: SELECTOR *sp = show_stat_selector(ph);
! 511: int idx = selector_get(sp);
! 512:
! 513: if (idx >= 0) {
! 514: NETSTAT **ns_list = (NETSTAT **)sp->list;
! 515: const NETSTAT *ns = ns_list[idx];
! 516:
! 517: for (idx = 0; idx < sp->items; idx++) {
! 518: if (netstat_bidir(ns, ns_list[idx])) {
! 519: selector_set(idx, sp);
! 520: return 1;
! 521: }
! 522: }
! 523: }
! 524: }
! 525: break;
! 526: }
! 527: return 0;
! 528: }
! 529:
! 530: SELECTOR *
! 531: show_stat_selector(ph)
! 532: PCAP_HANDLER *ph;
! 533: {
! 534: if (!ph) return 0;
! 535: if (!ph->selector && (ph->selector = selector_init()) != 0) {
! 536: ph->selector->get_header = show_stat_header;
! 537: ph->selector->get_line = show_stat_line;
! 538: ph->selector->get_footer = show_stat_footer;
! 539: }
! 540: return ph->selector;
! 541: }
! 542:
! 543: NETSTAT *
! 544: show_stat_get(ph, idx)
! 545: PCAP_HANDLER *ph;
! 546: int idx;
! 547: {
! 548: SELECTOR *sp;
! 549: NETSTAT **ns_list;
! 550:
! 551: /* sanity check */
! 552: if (!ph || idx < 0 || (sp = show_stat_selector(ph)) == 0 || idx >= sp->items)
! 553: return 0;
! 554:
! 555: ns_list = (NETSTAT **)sp->list;
! 556: return ns_list[idx];
! 557: }
! 558:
! 559: int
! 560: show_stat_search(ph, str)
! 561: PCAP_HANDLER *ph;
! 562: const char *str;
! 563: {
! 564: SELECTOR *sp;
! 565: NETSTAT **ns_list;
! 566: const NETSTAT *ns;
! 567: int idx;
! 568: char src_buf[100], dst_buf[100], proto_buf[20];
! 569:
! 570: /* sanity check */
! 571: if (!ph || !str || *str == '\0' || (sp = show_stat_selector(ph)) == 0)
! 572: return -1;
! 573:
! 574: ns_list = (NETSTAT **)sp->list;
! 575: for (idx = 0; idx < sp->items; idx++) {
! 576: ns = ns_list[idx];
! 577: hdr2str(&ns->ns_hdr,
! 578: src_buf, sizeof(src_buf),
! 579: dst_buf, sizeof(dst_buf),
! 580: proto_buf, sizeof(proto_buf));
! 581: if (strstr(src_buf, str) ||
! 582: strstr(dst_buf, str) ||
! 583: strstr(proto_buf, str))
! 584: return idx;
! 585: }
! 586: return -1;
! 587: }
! 588:
! 589: SELECTOR *
! 590: show_stat_list(ph)
! 591: PCAP_HANDLER *ph;
! 592: {
! 593: SELECTOR *sp;
! 594: int cnt;
! 595:
! 596: /* sanity check */
! 597: if (!ph || (sp = show_stat_selector(ph)) == 0)
! 598: return 0;
! 599:
! 600: sp->header = ph;
! 601: sp->footer = ph;
! 602:
! 603: if ((cnt = netstat_fetch((NETSTAT ***)&sp->list, ph)) < 0)
! 604: return sp;
! 605:
! 606: sp->items = cnt;
! 607: if (cnt < 2) /* no sorting required */
! 608: return sp;
! 609:
! 610: /* sort it accroding to current mode */
! 611: switch (show_stat_mode) {
! 612: case Size:
! 613: qsort(sp->list, sp->items, sizeof(NETSTAT *), compare_pkt_len);
! 614: break;
! 615: case Data:
! 616: qsort(sp->list, sp->items, sizeof(NETSTAT *), compare_data_len);
! 617: break;
! 618: case Packets:
! 619: qsort(sp->list, sp->items, sizeof(NETSTAT *), compare_pkt_cnt);
! 620: break;
! 621: }
! 622: if (popbackflow)
! 623: sort_backflow(sp->list, sp->items);
! 624:
! 625: return sp;
! 626: }
! 627:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>