/* * Copyright (c) 1993-1997 JSC Rinet, Novosibirsk, Russia * * Redistribution and use in source forms, with and without modification, * are permitted provided that this entire comment appears intact. * Redistribution in binary form may occur without any restrictions. * * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND. */ /* trafshow.c -- main code to cooperate with pcap and curses */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_SLCURSES #include #endif #ifdef HAVE_NCURSES #include #endif #ifdef HAVE_CURSES #include #endif #include #ifdef HAVE_SYS_IOCTL_H #include #endif #include #include #include #include #include #include "trafshow.h" #ifndef TIOCGWINSZ #define TIOCGWINSZ 104 #endif /* command line switches */ int fflag = 0; /* don't translate foreign IP address */ int nflag = 0; /* don't convert addresses to host names */ int Nflag = 0; /* output only host names without domain */ int Oflag = 1; /* don't run filter code optimizer */ int pflag = 0; /* don't put the interface into promiscuous mode */ int kflag = 1; /* disable keyboard input checking */ int eflag = 0; /* show ethernet traffic rather than ip */ /* global variables */ char *program_name; /* myself */ char *device_name; /* network interface name */ int alarm_flag = 0; /* flag -- screen refresh requested */ int scr_interval = DEFAULT_SCR; /* screen refresh interval in seconds */ int dns_timeout = DEFAULT_DNS; /* dns query timeout in seconds */ int snaplen = DEFAULT_SNAPLEN; /* length of saved portion of packet */ int curses_initialized = FALSE; int use_colors = FALSE; int resize_flag = 0; int addr_size, proto_size, bytes_size, cps_size, count_size; void main(argc, argv) int argc; char **argv; { int op, cnt; pcap_t *pd; bpf_u_int32 localnet, netmask; char *cp, *infile, *expr, ebuf[PCAP_ERRBUF_SIZE]; struct bpf_program fcode; extern char *optarg; extern int optind, opterr; void usage(), onalarm(), onwinch(), vers(); extern int abort_on_misalignment(); extern pcap_handler lookup_if(); cnt = -1; device_name = NULL; infile = NULL; if ((cp = (char *)strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; if (abort_on_misalignment(ebuf) < 0) error(0, ebuf); while ((op = getopt(argc, argv, "c:CefF:i:knNOpr:t:vh?")) != EOF) switch (op) { case 'C': #ifdef HAVE_SLCURSES use_colors = TRUE; #else error(0, "must be compiled with slang curses"); #endif break; case 'c': cnt = atoi(optarg); if (cnt < 1) usage(); break; case 'e': ++eflag; break; case 'f': ++fflag; break; case 'F': infile = optarg; break; case 'i': device_name = optarg; break; case 'k': kflag = 0; break; case 'n': ++nflag; break; case 'N': ++Nflag; break; case 'O': Oflag = 0; break; case 'p': ++pflag; break; case 'r': scr_interval = atoi(optarg); if (scr_interval < 1) usage(); break; case 't': dns_timeout = atoi(optarg); if (dns_timeout < 1) usage(); break; case 'v': vers(); case 'h': case '?': default: usage(); } /* Find network interface */ if (device_name == NULL && (device_name = pcap_lookupdev(ebuf)) == NULL) error(0, ebuf); /* Attach pcap to the network interface */ if ((pd = pcap_open_live(device_name, snaplen, !pflag, 1000, ebuf)) == NULL) error(0, ebuf); if ((op = pcap_snapshot(pd)) > snaplen) snaplen = op; op = pcap_datalink(pd); if (eflag && op != DLT_EN10MB #ifdef DLT_IEEE802 && op != DLT_IEEE802 #endif ) error(0, "interface %s not an Ethernet", device_name); if (pcap_lookupnet(device_name, &localnet, &netmask, ebuf) < 0) error(0, ebuf); /* Get back to user process after socket has been opened */ setuid(getuid()); /* Read out the user filter expression */ if (infile) expr = read_infile(infile); else expr = copy_argv(&argv[optind]); /* and compile it */ if (pcap_compile(pd, &fcode, expr, Oflag, netmask) < 0 || pcap_setfilter(pd, &fcode) < 0) error(0, pcap_geterr(pd)); init_addrtoname(localnet, netmask); init_term(FALSE); (void) signal(SIGHUP, cleanup); (void) signal(SIGINT, cleanup); (void) signal(SIGQUIT, cleanup); (void) signal(SIGTERM, cleanup); (void) signal(SIGALRM, onalarm); (void) signal(SIGWINCH, onwinch); init_display(FALSE); if (pcap_loop(pd, cnt, lookup_if(op), NULL) < 0) error(0, pcap_geterr(pd)); pcap_close(pd); cleanup(0); } /* * SIGALRM interrupt handler, should be ran each scr_interval seconds. */ void onalarm() { if (alarm_flag) { if (resize_flag) { resize_flag = 0; init_term(TRUE); } scr_redraw(TRUE); scr_update(); } else alarm(scr_interval); alarm_flag++; (void) signal(SIGALRM, onalarm); } void cleanup(sig) int sig; { #ifdef HAVE_HAS_COLORS if (use_colors) attrset(A_NORMAL); #endif if (sig == SIGINT) { move(LINES-1, 0); clrtoeol(); refresh(); } endwin(); exit(sig < 0 ? 1 : 0); } void init_term(reinit) int reinit; { float i; if (!reinit) { if (initscr() == (WINDOW *)ERR) error(0, "Can't initialize terminal -- unknown terminal type?"); curses_initialized = TRUE; #ifdef HAVE_HAS_COLORS if (use_colors == FALSE) use_colors = has_colors(); #ifdef HAVE_SLCURSES else SLtt_Use_Ansi_Colors = TRUE; #endif if (use_colors == TRUE) { start_color(); if (init_colormask() == 0) use_colors = FALSE; } #endif cbreak(); noecho(); } else { #ifdef HAVE_RESIZETERM struct winsize ws; if (ioctl(0, TIOCGWINSZ, &ws) == 0) resizeterm(ws.ws_row, ws.ws_col); #else /* assume it will work on all curses without resizeterm() */ endwin(); initscr(); cbreak(); noecho(); #endif } if (LINES < 10) error(0, "Must more LINES on term; cur %d min %d", LINES, 10); if (COLS < 40) error(0, "Must more COLS on term; cur %d min %d", COLS, 40); page_size = LINES - SCR_OFFS - 2; i = (float)COLS / (float)DEFAULT_COLS; addr_size = i * (float)ADDR_SIZE; proto_size = i * (float)PROTO_SIZE; bytes_size = i * (float)BYTES_SIZE; cps_size = i * (float)CPS_SIZE; count_size = i * (float)COUNT_SIZE; clear(); header_line(); if (reinit) init_display(TRUE); else scr_update(); } void onwinch() { alarm_flag++; resize_flag++; (void) signal(SIGWINCH, onwinch); } void vers() { int hc; extern char version[], compiled[], target[], libpcap[], copyright[]; #ifdef HAVE_HAS_COLORS initscr(); hc = has_colors(); endwin(); #endif fprintf(stderr, "\n%s version %s\ncompiled for %s with\n %s\n", program_name, version, target, compiled); fprintf(stderr, "\tpcap library version %s\n", libpcap); #ifdef HAVE_SLCURSES fprintf(stderr, "\tslang curses version %d\n", SLang_Version); #endif #ifdef HAVE_NCURSES #ifdef NCURSES_VERSION fprintf(stderr, "\tncurses version %s\n", NCURSES_VERSION); #else fprintf(stderr, "\tncurses version unknown\n"); #endif #endif #ifdef HAVE_CURSES fprintf(stderr, "\tunknown curses library\n"); #endif #ifdef HAVE_HAS_COLORS fprintf(stderr, "\tcolors support\n"); if (hc) fprintf(stderr, "your current terminal has color capability\n"); else fprintf(stderr, "your current terminal has no color capability\n\ \ttry -C option to force ansi color mode\n"); #else fprintf(stderr, "\tno colors support\n"); #endif fprintf(stderr, "\n%s\n", copyright); fprintf(stderr,"For bugs report email to trafshow@rinet.nsk.su (include this page)\n"); exit(1); } void usage() { fprintf(stderr, "Usage: %s [-eCfknNOpv -c num -i name -r sec -t sec] [-F file | expr]\n\ \t-c number\tcount number of packets and exit\n\ \t-C\t\tforce color mode (when color capability is missing)\n\ \t-e\t\tshow Ethernet traffic rather than IP\n\ \t-f\t\tconvert addresses to name only for local hosts\n\ \t-F file\t\tuse file as input for the filter expression\n\ \t-i name\t\tnetwork interface name; ef0, sl0, ppp0, lo0, etc\n\ \t-k\t\tdisable keyboard input checking\n\ \t-n\t\tdon't convert addresses to host names\n\ \t-N\t\toutput only host names without domain\n\ \t-O\t\tdon't run the packet-matching code optimizer\n\ \t-p\t\tdon't put the interface into promiscuous mode\n\ \t-r seconds\tscreen refresh interval, default %d sec\n\ \t-t seconds\tmax timeout in DNS query, default %d sec\n\ \t-v\t\tprint version information\n\ \texpr\t\tfilter expression like tcpdump's\n", program_name, DEFAULT_SCR, DEFAULT_DNS); exit(1); }