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>