Annotation of embedaddon/trafshow/show_dump.c, revision 1.1.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>