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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>