File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / trafshow / show_dump.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:55:18 2012 UTC (12 years, 4 months ago) by misho
Branches: trafshow, MAIN
CVS tags: v5_2_3p0, v5_2_3, HEAD
trafshow

    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>