Annotation of embedaddon/trafshow/show_dump.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 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: #ifdef HAVE_SLCURSES
! 15: #include <slcurses.h>
! 16: #elif HAVE_NCURSES
! 17: #include <ncurses.h>
! 18: #else
! 19: #include <curses.h>
! 20: #endif
! 21: #include <sys/param.h>
! 22: #include <sys/types.h>
! 23: #include <sys/socket.h>
! 24: #include <sys/time.h>
! 25: #include <netinet/in.h>
! 26: #include <arpa/inet.h>
! 27: #include <stdio.h>
! 28: #include <stdlib.h>
! 29: #include <string.h>
! 30: #include <unistd.h>
! 31: #include <errno.h>
! 32: #include <pcap.h>
! 33: #include <pthread.h>
! 34: #include <time.h>
! 35: #include <ctype.h>
! 36:
! 37: #include "show_dump.h"
! 38: #include "show_stat.h" /* just for hdr2str() */
! 39: #include "parse_dl.h"
! 40: #include "trafshow.h"
! 41: #include "screen.h"
! 42: #include "netstat.h"
! 43: #include "getkey.h"
! 44: #include "addrtoname.h"
! 45: #include "util.h"
! 46:
! 47: NETSTAT *dump_match = 0;
! 48: const char *cisco_netflow_dump = 0;
! 49: const char *dump_file = 0;
! 50:
! 51: static char *build_filter_expr(char *dst, int size, const NETSTAT *ns);
! 52: static void *live_pcap_dump();
! 53: static void live_pcap_parse(u_char *a, const struct pcap_pkthdr *h, const u_char *p);
! 54: static void file_pcap_parse(u_char *a, const struct pcap_pkthdr *h, const u_char *p);
! 55: static void show_header_dump(PCAP_HANDLER *ph, const NETSTAT *ns);
! 56: static void show_ascii_dump(const u_char *p, int length);
! 57: static void show_hex_dump(const u_char *p, int length);
! 58:
! 59: static pcap_t *live_pcap = 0;
! 60: static pcap_dumper_t *live_dump = 0;
! 61: static pthread_t *live_pcap_thr = 0;
! 62: static pcap_t *file_pcap = 0;
! 63: static FILE *file_netflow = 0;
! 64: static int redraw_lines = 0;
! 65:
! 66: static void
! 67: print_mode(void)
! 68: {
! 69: const char *cp = cisco_netflow_dump;
! 70: char src_buf[100], dst_buf[100], proto_buf[20];
! 71:
! 72: /* sanity check */
! 73: if (!dump_match) return;
! 74:
! 75: hdr2str(&dump_match->ns_hdr,
! 76: src_buf, sizeof(src_buf),
! 77: dst_buf, sizeof(dst_buf),
! 78: proto_buf, sizeof(proto_buf));
! 79:
! 80: if (!cisco_netflow_dump) {
! 81: switch (show_stat_mode) {
! 82: case Size: cp = "HexData"; break;
! 83: case Data: cp = "AsciiData"; break;
! 84: case Packets: cp = "Packets"; break;
! 85: }
! 86: }
! 87:
! 88: attrset(A_STANDOUT);
! 89: printw("\n--- %s %s > %s %s flow ---",
! 90: proto_buf, src_buf, dst_buf, cp);
! 91: attrset(A_NORMAL);
! 92:
! 93: #ifdef HAVE_WREDRAWLN
! 94: wredrawln(stdscr, 0, LINES);
! 95: #endif
! 96: refresh();
! 97: }
! 98:
! 99: #ifndef HAVE_PCAP_DUMP_FLUSH
! 100: int
! 101: pcap_dump_flush(pcap_dumper_t *p)
! 102: {
! 103:
! 104: if (fflush((FILE *)p) == EOF)
! 105: return (-1);
! 106: else
! 107: return (0);
! 108: }
! 109: #endif
! 110:
! 111: int
! 112: show_dump_open(ph, ns)
! 113: const PCAP_HANDLER *ph;
! 114: const NETSTAT *ns;
! 115: {
! 116: int op;
! 117: struct bpf_program filter;
! 118: bpf_u_int32 net;
! 119: bpf_u_int32 mask;
! 120: char name[100], buf[256];
! 121:
! 122: /* sanity check */
! 123: if (!ph || !ns) return -1;
! 124:
! 125: show_dump_close();
! 126:
! 127: if (!dump_match && (dump_match = (NETSTAT *)malloc(sizeof(NETSTAT))) == 0) {
! 128: screen_status("%s: malloc: Out of memory?", ph->name);
! 129: show_dump_close();
! 130: return -1;
! 131: }
! 132: memcpy(dump_match, ns, sizeof(NETSTAT));
! 133:
! 134: if (ph->pcap) {
! 135: /* open live packet capture */
! 136: buf[0] = '\0';
! 137: live_pcap = pcap_open_live(strcpy(name, ph->name),
! 138: DUMP_SNAPLEN, promisc, 1, buf);
! 139: if (buf[0] != '\0')
! 140: screen_status("%s: %s", ph->name, buf);
! 141: if (!live_pcap) return -1;
! 142: #ifdef notdef
! 143: if (pcap_setnonblock(live_pcap, 1, buf) < 0) {
! 144: screen_status("%s: %s", ph->name, buf);
! 145: show_dump_close();
! 146: return -1;
! 147: }
! 148: #endif
! 149: /* setup filter expression */
! 150: if (pcap_lookupnet(strcpy(name, ph->name), &net, &mask, buf) < 0) {
! 151: /* ignore error */
! 152: net = 0;
! 153: mask = 0;
! 154: }
! 155: if (!build_filter_expr(buf, sizeof(buf), ns)) {
! 156: screen_status("%s: Can't build filter expression", ph->name);
! 157: show_dump_close();
! 158: return -1;
! 159: }
! 160: if (pcap_compile(live_pcap, &filter, buf, Oflag, mask) < 0) {
! 161: screen_status("%s: %s", ph->name, pcap_geterr(live_pcap));
! 162: show_dump_close();
! 163: return -1;
! 164: }
! 165: op = pcap_setfilter(live_pcap, &filter);
! 166: pcap_freecode(&filter);
! 167: if (op < 0) {
! 168: screen_status("%s: %s", ph->name, pcap_geterr(live_pcap));
! 169: show_dump_close();
! 170: return -1;
! 171: }
! 172: } else if ((cisco_netflow_dump = strdup(ph->name)) == 0) {
! 173: screen_status("%s: strdup: Out of memory?", ph->name);
! 174: show_dump_close();
! 175: return -1;
! 176: }
! 177:
! 178: /* open pcap dump file for writing */
! 179:
! 180: snprintf(buf, sizeof(buf), "%s/%s.XXXXXX", TEMP_DIR, progname);
! 181: if ((op = mkstemp(buf)) < 0) {
! 182: screen_status("%s: %s: %s",
! 183: ph->name, buf, strerror(errno));
! 184: show_dump_close();
! 185: return -1;
! 186: }
! 187: (void)close(op);
! 188: if ((dump_file = strdup(buf)) == 0) {
! 189: screen_status("%s: strdup: Out of memory?", ph->name);
! 190: show_dump_close();
! 191: return -1;
! 192: }
! 193:
! 194: if (!cisco_netflow_dump) {
! 195: if ((live_dump = pcap_dump_open(live_pcap, dump_file)) == 0) {
! 196: screen_status("%s: %s", ph->name, pcap_geterr(live_pcap));
! 197: show_dump_close();
! 198: return -1;
! 199: }
! 200: pcap_dump_flush(live_dump); /* write header right now */
! 201:
! 202: /* spawn thread to dump live packet capture into the file */
! 203: if ((live_pcap_thr = (pthread_t *)malloc(sizeof(pthread_t))) == 0) {
! 204: screen_status("%s: malloc: Out of memory?", ph->name);
! 205: show_dump_close();
! 206: return -1;
! 207: }
! 208: if (pthread_create(live_pcap_thr, 0, live_pcap_dump, 0)) {
! 209: screen_status("%s: pthread_create: Out of resources?", ph->name);
! 210: show_dump_close();
! 211: return -1;
! 212: }
! 213:
! 214: /* open pcap dump file for reading */
! 215: if ((file_pcap = pcap_open_offline(dump_file, buf)) == 0) {
! 216: screen_status("%s: %s", ph->name, buf);
! 217: show_dump_close();
! 218: return -1;
! 219: }
! 220: } else if ((file_netflow = fopen(dump_file, "r")) == 0) {
! 221: screen_status("%s: %s: %s",
! 222: ph->name, dump_file, strerror(errno));
! 223: show_dump_close();
! 224: return -1;
! 225: }
! 226:
! 227: scrollok(stdscr, 1);
! 228: screen_clear();
! 229: print_mode();
! 230: return 0;
! 231: }
! 232:
! 233: static void *
! 234: live_pcap_dump()
! 235: {
! 236: int op;
! 237:
! 238: while (live_pcap && live_dump) {
! 239: op = pcap_dispatch(live_pcap, -1, live_pcap_parse,
! 240: (u_char *)live_dump);
! 241: if (op == -2 || (op == -1 && errno != EAGAIN))
! 242: break;
! 243: if (op < 1) usleep(1000); /* 1ms idle to prevent deadloop */
! 244: }
! 245: return 0;
! 246: }
! 247:
! 248: static void
! 249: live_pcap_parse(a, h, p)
! 250: u_char *a;
! 251: const struct pcap_pkthdr *h;
! 252: const u_char *p;
! 253: {
! 254: NETSTAT ns;
! 255:
! 256: /* sanity check */
! 257: if (!a || !live_pcap) return;
! 258:
! 259: memset(&ns, 0, sizeof(NETSTAT));
! 260:
! 261: if (parse_dl(&ns, pcap_datalink(live_pcap), h->caplen, h->len, p) < 0)
! 262: return;
! 263:
! 264: if (!netstat_match(&ns, dump_match))
! 265: return;
! 266:
! 267: pcap_dump(a, h, p);
! 268: pcap_dump_flush((pcap_dumper_t *)a);
! 269: }
! 270:
! 271: void
! 272: show_dump_close()
! 273: {
! 274: if (cisco_netflow_dump) {
! 275: free((char *)cisco_netflow_dump);
! 276: cisco_netflow_dump = 0;
! 277: }
! 278: if (file_netflow) {
! 279: (void)fclose(file_netflow);
! 280: file_netflow = 0;
! 281: }
! 282:
! 283: if (live_pcap_thr) {
! 284: pthread_cancel(*live_pcap_thr);
! 285: free(live_pcap_thr);
! 286: live_pcap_thr = 0;
! 287: }
! 288: if (live_dump) {
! 289: pcap_dump_close(live_dump);
! 290: live_dump = 0;
! 291: }
! 292: if (live_pcap) {
! 293: pcap_close(live_pcap);
! 294: live_pcap = 0;
! 295: }
! 296: if (file_pcap) {
! 297: pcap_close(file_pcap);
! 298: file_pcap = 0;
! 299: }
! 300:
! 301: if (dump_file) {
! 302: (void)unlink(dump_file);
! 303: free((char *)dump_file);
! 304: dump_file = 0;
! 305: }
! 306: scrollok(stdscr, 0);
! 307: }
! 308:
! 309: void
! 310: show_dump_print(ph)
! 311: PCAP_HANDLER *ph;
! 312: {
! 313: if (!cisco_netflow_dump) {
! 314: int op;
! 315:
! 316: /* sanity check */
! 317: if (!file_pcap) return;
! 318:
! 319: clearerr(pcap_file(file_pcap)); /* tail file */
! 320: while ((op = pcap_dispatch(file_pcap, -1, file_pcap_parse,
! 321: (u_char *)ph)) > 0);
! 322: if (op < 0) {
! 323: if (op == -1)
! 324: screen_status(pcap_geterr(file_pcap));
! 325: return;
! 326: }
! 327: } else {
! 328: char *cp, buf[256];
! 329:
! 330: /* sanity check */
! 331: if (!file_netflow) return;
! 332:
! 333: clearerr(file_netflow); /* tail file */
! 334: while (fgets(buf, sizeof(buf), file_netflow) != 0) {
! 335: buf[sizeof(buf)-1] = '\0';
! 336: if ((cp = strpbrk(buf, "\r\n")) != '\0')
! 337: *cp = '\0';
! 338: printw("%s\n", buf);
! 339: redraw_lines++;
! 340: }
! 341: }
! 342: if (redraw_lines) {
! 343: #ifdef HAVE_WREDRAWLN
! 344: wredrawln(stdscr, 0, LINES);
! 345: #endif
! 346: refresh();
! 347: redraw_lines = 0;
! 348: }
! 349: }
! 350:
! 351: static void
! 352: file_pcap_parse(a, h, p)
! 353: u_char *a;
! 354: const struct pcap_pkthdr *h;
! 355: const u_char *p;
! 356: {
! 357: PCAP_HANDLER *ph = (PCAP_HANDLER *)a;
! 358: FILE *fp;
! 359: long sz;
! 360: int hdrlen;
! 361: NETSTAT ns;
! 362:
! 363: /* sanity check */
! 364: if (!file_pcap) return;
! 365:
! 366: /* prevent huge output */
! 367: if ((fp = pcap_file(file_pcap)) == 0 || (sz = fd_size(fileno(fp))) < 0)
! 368: return;
! 369: if (sz - ftell(fp) > DUMP_SNAPLEN * LINES)
! 370: return;
! 371:
! 372: memset(&ns, 0, sizeof(NETSTAT));
! 373:
! 374: hdrlen = parse_dl(&ns, pcap_datalink(file_pcap), h->caplen, h->len, p);
! 375: if (hdrlen < 0 || hdrlen > h->caplen)
! 376: return;
! 377:
! 378: if (!netstat_match(&ns, dump_match))
! 379: return;
! 380:
! 381: ns.mtime = h->ts;
! 382:
! 383: switch (show_stat_mode) {
! 384: case Size:
! 385: show_hex_dump(p + hdrlen, h->caplen - hdrlen);
! 386: break;
! 387: case Data:
! 388: show_ascii_dump(p + hdrlen, h->caplen - hdrlen);
! 389: break;
! 390: case Packets:
! 391: show_header_dump(ph, &ns);
! 392: break;
! 393: }
! 394: }
! 395:
! 396: void
! 397: show_dump_input(ch)
! 398: int ch;
! 399: {
! 400: if (ch == 'c' || ch == 'C' || ch == K_CTRL('R'))
! 401: screen_clear();
! 402: else if (show_stat_input(0, ch))
! 403: print_mode();
! 404: }
! 405:
! 406: static char *
! 407: build_filter_expr(dst, size, ns)
! 408: char *dst;
! 409: int size;
! 410: const NETSTAT *ns;
! 411: {
! 412: char src_addr[100], dst_addr[100];
! 413:
! 414: src_addr[0] = '\0';
! 415: dst_addr[0] = '\0';
! 416:
! 417: if (ns->ip_ver == 4) {
! 418: (void)strcpy(src_addr, intoa(ns->ip_src_addr.ip_addr.s_addr));
! 419: (void)strcpy(dst_addr, intoa(ns->ip_dst_addr.ip_addr.s_addr));
! 420: }
! 421: #ifdef INET6
! 422: else if (ns->ip_ver == 6) {
! 423: (void)inet_ntop(AF_INET6, &ns->ip_src_addr.ip6_addr, src_addr, sizeof(src_addr));
! 424: (void)inet_ntop(AF_INET6, &ns->ip_dst_addr.ip6_addr, dst_addr, sizeof(dst_addr));
! 425: }
! 426: #endif
! 427: else if (ns->eth_type) {
! 428: (void)strcpy(src_addr, etheraddr_string(ns->eth_src_addr));
! 429: (void)strcpy(dst_addr, etheraddr_string(ns->eth_dst_addr));
! 430: }
! 431:
! 432: if (src_addr[0] == '\0' || dst_addr[0] == '\0')
! 433: return 0; /* should not happen */
! 434:
! 435: if (ns->ip_ver) {
! 436: snprintf(dst, size,
! 437: "src %s and dst %s",
! 438: src_addr, dst_addr);
! 439: } else if (!strcmp(dst_addr, "broadcast") ||
! 440: !strcmp(dst_addr, "multicast")) {
! 441: snprintf(dst, size,
! 442: "ether src %s and ether %s",
! 443: src_addr, dst_addr);
! 444: } else {
! 445: snprintf(dst, size,
! 446: "ether src %s and ether dst %s",
! 447: src_addr, dst_addr);
! 448: }
! 449: return dst;
! 450: }
! 451:
! 452: static void
! 453: show_header_dump(ph, ns)
! 454: PCAP_HANDLER *ph;
! 455: const NETSTAT *ns;
! 456: {
! 457: char time_buf[100], src_buf[100], dst_buf[100], proto_buf[20];
! 458: #ifdef notdef
! 459: NETSTAT find = *ns;
! 460: if (netstat_find(ph, &find))
! 461: ns = &find;
! 462: #endif
! 463: (void)strftime(time_buf, sizeof(time_buf),
! 464: "%T", localtime((time_t *)&ns->mtime.tv_sec));
! 465: hdr2str(&ns->ns_hdr,
! 466: src_buf, sizeof(src_buf),
! 467: dst_buf, sizeof(dst_buf),
! 468: proto_buf, sizeof(proto_buf));
! 469:
! 470: printw("\n%s.%03d %s %s > %s %d/%d bytes",
! 471: time_buf, (int)(ns->mtime.tv_usec / 1000),
! 472: proto_buf, src_buf, dst_buf,
! 473: (int)ns->pkt_len, (int)ns->data_len);
! 474:
! 475: redraw_lines++;
! 476: }
! 477:
! 478: static void
! 479: show_ascii_dump(cp, length)
! 480: const u_char *cp;
! 481: int length;
! 482: {
! 483: /* sanity check */
! 484: if (!cp || length < 1)
! 485: return;
! 486:
! 487: if (!redraw_lines)
! 488: addch('\n');
! 489: while (--length >= 0) {
! 490: if (*cp != '\r' && *cp != '\b')
! 491: addch(*cp);
! 492: cp++;
! 493: }
! 494: redraw_lines++;
! 495: }
! 496:
! 497: #ifdef ACS_VLINE
! 498: #define VLINE ACS_VLINE
! 499: #else
! 500: #define VLINE '|'
! 501: #endif
! 502:
! 503: /* stolen from tcpdump's ascii-print() */
! 504:
! 505: #define HEXDUMP_BYTES_PER_LINE 16
! 506: #define HEXDUMP_SHORTS_PER_LINE (HEXDUMP_BYTES_PER_LINE / 2)
! 507: #define HEXDUMP_HEXSTUFF_PER_SHORT 5 /* 4 hex digits and a space */
! 508: #define HEXDUMP_HEXSTUFF_PER_LINE \
! 509: (HEXDUMP_HEXSTUFF_PER_SHORT * HEXDUMP_SHORTS_PER_LINE)
! 510:
! 511: static void
! 512: show_hex_dump(cp, length)
! 513: const u_char *cp;
! 514: int length;
! 515: {
! 516: int oset = 0;
! 517: register u_int i;
! 518: register int s1, s2;
! 519: register int nshorts;
! 520: char hexstuff[HEXDUMP_SHORTS_PER_LINE*HEXDUMP_HEXSTUFF_PER_SHORT+1], *hsp;
! 521: char asciistuff[100], *asp;
! 522: u_int maxlength = HEXDUMP_SHORTS_PER_LINE;
! 523:
! 524: /* sanity check */
! 525: if (!cp || length < 1)
! 526: return;
! 527:
! 528: nshorts = length / sizeof(u_short);
! 529: i = 0;
! 530: hsp = hexstuff;
! 531: asp = asciistuff;
! 532: while (--nshorts >= 0) {
! 533: s1 = *cp++;
! 534: s2 = *cp++;
! 535: (void)snprintf(hsp, sizeof(hexstuff) - (hsp - hexstuff),
! 536: " %02x%02x", s1, s2);
! 537: hsp += HEXDUMP_HEXSTUFF_PER_SHORT;
! 538: *(asp++) = (isgraph(s1) ? s1 : '.');
! 539: *(asp++) = (isgraph(s2) ? s2 : '.');
! 540: if (++i >= maxlength) {
! 541: i = 0;
! 542: *hsp = *asp = '\0';
! 543:
! 544: printw("\n0x%04X ", oset);
! 545: addch(VLINE);
! 546: printw("%-*s ", HEXDUMP_HEXSTUFF_PER_LINE, hexstuff);
! 547: addch(VLINE);
! 548: addch(' ');
! 549: addstr(asciistuff);
! 550:
! 551: hsp = hexstuff;
! 552: asp = asciistuff;
! 553: oset += HEXDUMP_BYTES_PER_LINE;
! 554:
! 555: redraw_lines++;
! 556: }
! 557: }
! 558: if (length & 1) {
! 559: s1 = *cp++;
! 560: (void)snprintf(hsp, sizeof(hexstuff) - (hsp - hexstuff),
! 561: " %02x", s1);
! 562: hsp += 3;
! 563: *(asp++) = (isgraph(s1) ? s1 : '.');
! 564: ++i;
! 565: }
! 566: if (i > 0) {
! 567: *hsp = *asp = '\0';
! 568:
! 569: printw("\n0x%04X ", oset);
! 570: addch(VLINE);
! 571: printw("%-*s ", HEXDUMP_HEXSTUFF_PER_LINE, hexstuff);
! 572: addch(VLINE);
! 573: addch(' ');
! 574: addstr(asciistuff);
! 575:
! 576: redraw_lines++;
! 577: }
! 578: }
! 579:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>