home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: ngrep.c,v 1.37 2000/02/01 12:28:02 jpr5 Exp $
- *
- */
-
- #if defined(BSD) || defined(SOLARIS)
- #include <unistd.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <net/if.h>
- #endif
-
- #if defined(OSF1)
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <net/route.h>
- #include <sys/mbuf.h>
- #endif
-
- #if defined(LINUX)
- #include <getopt.h>
- #endif
-
-
- #include <netinet/ip.h>
- #include <netinet/tcp.h>
- #include <netinet/udp.h>
- #include <netinet/ip_icmp.h>
-
- #include <pcap.h>
- #include <net/bpf.h>
-
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
-
- #include "regex.h"
- #include "ngrep.h"
-
-
- static char rcsver[] = "$Revision: 1.37 $";
-
- int snaplen = 65535, promisc = 1, to = 1000;
- int show_empty = 0, show_hex = 0, quiet = 0;
- int match_after = 0, keep_matching = 0, invert_match = 0;
- int matches = 0, max_matches = 0;
-
- char pc_err[PCAP_ERRBUF_SIZE], *re_err;
-
- int re_match_word = 0, re_ignore_case = 0;
- char *regex = NULL, *filter = NULL;
- struct re_pattern_buffer pattern;
- int (*match_func)();
-
- struct bpf_program pcapfilter;
- struct in_addr net, mask;
- char *dev = NULL;
- int link_offset;
- pcap_t *pd;
-
-
- int main(int argc, char **argv) {
- int c;
-
- signal(SIGINT, clean_exit);
- signal(SIGQUIT, clean_exit);
- signal(SIGABRT, clean_exit);
- signal(SIGPIPE, clean_exit);
-
- while ((c = getopt(argc, argv, "hViwqevxln:d:A:")) != EOF) {
- switch (c) {
- case 'A':
- match_after = atoi(optarg) + 1;
- break;
- case 'd':
- dev = optarg;
- break;
- case 'n':
- max_matches = atoi(optarg);
- break;
- case 'l':
- setvbuf(stdout, NULL, _IOLBF, 0);
- break;
- case 'x':
- show_hex++;
- break;
- case 'v':
- invert_match++;
- break;
- case 'e':
- show_empty++;
- break;
- case 'q':
- quiet++;
- break;
- case 'w':
- re_match_word++;
- break;
- case 'i':
- re_ignore_case++;
- break;
- case 'V':
- version();
- case 'h':
- usage(0);
- default:
- usage(-1);
- }
- }
-
- if (argv[optind])
- regex = argv[optind++];
-
-
- if (!dev)
- if (!(dev = pcap_lookupdev(pc_err))) {
- perror(pc_err);
- exit(-1);
- }
-
-
- if ((pd = pcap_open_live(dev, snaplen, promisc, to, pc_err)) == NULL) {
- perror(pc_err);
- exit(-1);
- }
-
- if (pcap_lookupnet(dev, &net.s_addr, &mask.s_addr, pc_err) == -1) {
- perror(pc_err);
- memset(&net, 0, sizeof(net));
- memset(&mask, 0, sizeof(mask));
- }
-
- if (!quiet) {
- printf("interface: %s", dev);
- if (net.s_addr && mask.s_addr) {
- printf(" (%s/", inet_ntoa(net));
- printf("%s)", inet_ntoa(mask));
- }
- printf("\n");
- }
-
-
- if (argv[optind]) {
- filter = get_filter(&argv[optind]);
-
- if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) {
- free(filter);
- filter = get_filter(&argv[optind-1]);
-
- PCAP_RESTART();
- if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) {
- pcap_perror(pd, "pcap compile");
- exit(-1);
- } else regex = NULL;
- }
-
- if (!quiet) printf("filter: %s\n", filter);
-
- if (pcap_setfilter(pd, &pcapfilter)) {
- pcap_perror(pd, "pcap set");
- exit(-1);
- }
- }
-
-
- if (regex) {
- match_func = &re_match_func;
- re_syntax_options = RE_SYNTAX_EGREP;
-
- if (re_ignore_case) {
- char *s;
- int i;
-
- pattern.translate = (char*)malloc(256);
- s = pattern.translate;
- for (i = 0; i < 256; i++)
- s[i] = i;
- for (i = 'A'; i <= 'Z'; i++)
- s[i] = i + 32;
-
- s = regex;
- while (*s)
- *s++ = tolower(*s);
- } else pattern.translate = NULL;
-
- if (re_match_word) {
- char *word_regex = malloc(strlen(regex) * 3 + strlen(WORD_REGEX));
- sprintf(word_regex, WORD_REGEX, regex, regex, regex);
- regex = word_regex;
- }
-
- (const char *)re_err = re_compile_pattern(regex, strlen(regex), &pattern);
- if (re_err) {
- fprintf(stderr, "regex compile: %s\n", re_err);
- exit(-1);
- }
-
- pattern.fastmap = (char*)malloc(256);
- if (re_compile_fastmap(&pattern)) {
- perror("fastmap compile failed");
- exit(-1);
- }
-
- if (!quiet && regex && strlen(regex))
- printf("%smatch: %s\n", invert_match?"don't ":"", regex);
- } else match_func = &blank_match_func;
-
-
- if (re_match_word) free(regex);
- if (filter) free(filter);
-
-
- switch(pcap_datalink(pd)) {
- case DLT_EN10MB:
- case DLT_IEEE802:
- link_offset = ETHHDR_SIZE;
- break;
-
- case DLT_FDDI:
- link_offset = FDDIHDR_SIZE;
- break;
-
- case DLT_SLIP:
- link_offset = SLIPHDR_SIZE;
- break;
-
- case DLT_PPP:
- link_offset = PPPHDR_SIZE;
- break;
-
- case DLT_RAW:
- link_offset = RAWHDR_SIZE;
- break;
-
- case DLT_NULL:
- link_offset = LOOPHDR_SIZE;
- break;
-
- default:
- fprintf(stderr, "fatal: unsupported interface type\n");
- exit(-1);
- }
-
-
- while (pcap_loop(pd, 0, (pcap_handler)process, 0));
- }
-
-
- void process(u_char *data1, struct pcap_pkthdr* h, u_char *p) {
- struct ip* ip_packet = (struct ip *)(p + link_offset);
-
- unsigned ip_hl = ip_packet->ip_hl*4;
- unsigned ip_off = ntohs(ip_packet->ip_off);
- unsigned fragmented = ip_off & (IP_MF | IP_OFFMASK);
- unsigned frag_offset = fragmented?(ip_off & IP_OFFMASK) * 8:0;
-
- char *data;
- int len;
-
- switch (ip_packet->ip_p) {
- case IPPROTO_TCP: {
- struct tcphdr* tcp = (struct tcphdr *)(((char *)ip_packet) + ip_hl);
- unsigned tcphdr_offset = fragmented?0:(tcp->th_off * 4);
-
- if (!quiet) {
- printf("#");
- fflush(stdout);
- }
-
- data = ((char*)tcp) + tcphdr_offset;
- len = ntohs(ip_packet->ip_len) - ip_hl - tcphdr_offset;
-
- if (((len || show_empty) && (((int)(*match_func)(data, len)) != invert_match))
- || keep_matching) {
- printf("\nT ");
-
- if (tcphdr_offset || !frag_offset) {
- printf("%s:%d -", inet_ntoa(ip_packet->ip_src), ntohs(tcp->th_sport));
- printf("> %s:%d", inet_ntoa(ip_packet->ip_dst), ntohs(tcp->th_dport));
- printf(" [%s%s%s%s%s%s]",
- (tcp->th_flags & TH_ACK)?"A":"",
- (tcp->th_flags & TH_SYN)?"S":"",
- (tcp->th_flags & TH_RST)?"R":"",
- (tcp->th_flags & TH_FIN)?"F":"",
- (tcp->th_flags & TH_URG)?"U":"",
- (tcp->th_flags & TH_PUSH)?"P":"");
- } else {
- printf("%s -", inet_ntoa(ip_packet->ip_src));
- printf("> %s", inet_ntoa(ip_packet->ip_dst));
- }
-
- if (fragmented) {
- printf(" %s%d@%d:%d\n", frag_offset?"+":"", ntohs(ip_packet->ip_id),
- frag_offset, len);
- } else printf("\n");
-
- dump(data,len);
- }
- }
- break;
-
- case IPPROTO_UDP: {
- struct udphdr* udp = (struct udphdr *)(((char *)ip_packet) + ip_hl);
- unsigned udphdr_offset = (fragmented)?0:sizeof(struct udphdr);
-
- if (!quiet) {
- printf("#");
- fflush(stdout);
- }
-
- data = ((char*)udp) + udphdr_offset;
- len = ntohs(ip_packet->ip_len) - ip_hl - udphdr_offset;
-
- if (((len || show_empty) && (((int)(*match_func)(data, len)) != invert_match))
- || keep_matching) {
- printf("\nU ");
-
- if (udphdr_offset || !frag_offset) {
- #ifdef HAVE_DUMB_UDPHDR
- printf("%s:%d -", inet_ntoa(ip_packet->ip_src), ntohs(udp->source));
- printf("> %s:%d", inet_ntoa(ip_packet->ip_dst), ntohs(udp->dest));
- #else
- printf("%s:%d -", inet_ntoa(ip_packet->ip_src), ntohs(udp->uh_sport));
- printf("> %s:%d", inet_ntoa(ip_packet->ip_dst), ntohs(udp->uh_dport));
- #endif
- } else {
- printf("%s -", inet_ntoa(ip_packet->ip_src));
- printf("> %s", inet_ntoa(ip_packet->ip_dst));
- }
-
- if (fragmented) {
- printf(" %s%d@%d:%d\n", frag_offset?"+":"", ntohs(ip_packet->ip_id),
- frag_offset, len);
- } else printf("\n");
-
- dump(data,len);
- }
- }
- break;
-
- case IPPROTO_ICMP: {
- struct icmp* ic = (struct icmp *)(((char *)ip_packet) + ip_hl);
- unsigned icmphdr_offset = fragmented?0:4;
-
- if (!quiet) {
- printf("#");
- fflush(stdout);
- }
-
- data = ((char*)ic) + icmphdr_offset;
- len = ntohs(ip_packet->ip_len) - ip_hl - icmphdr_offset;
-
- if (((len || show_empty) && (((int)(*match_func)(data, len)) != invert_match))
- || keep_matching) {
- printf("\nI ");
-
- printf("%s -", inet_ntoa(ip_packet->ip_src));
- printf("> %s", inet_ntoa(ip_packet->ip_dst));
-
- if (icmphdr_offset || !frag_offset)
- printf(" %d:%d", ic->icmp_type, ic->icmp_code);
-
- if (fragmented) {
- printf(" %s%d@%d:%d\n", frag_offset?"+":"", ntohs(ip_packet->ip_id),
- frag_offset, len);
- } else printf("\n");
- dump(data,len);
- }
- }
- break;
-
- }
-
- if (match_after && keep_matching)
- keep_matching--;
- }
-
-
- void dump(char *data, int len) {
- if (len > 0) {
- unsigned width = show_hex?16:70;
- char *str = data;
- int j, i = 0;
-
- while (i < len) {
- printf(" ");
-
- if (show_hex)
- for (j = 0; j < width; j++) {
- if (i+j < len)
- printf("%02x ", (unsigned char)str[j]);
- else printf(" ");
-
- if((j+1) % (width/2) == 0)
- printf(" ");
- }
-
- for (j = 0; j < width; j++)
- if (i+j < len)
- printf("%c", isprint(str[j])?str[j]:'.');
- else printf(" ");
-
- str += width;
- i += j;
-
- printf("\n");
- }
- }
- }
-
-
- int re_match_func(char *data, int len) {
- switch (re_search(&pattern, data, len, 0, len, 0)) {
- case -2:
- perror("she's dead, jim\n");
- exit(-1);
- case -1:
- return 0;
- }
-
- if (max_matches && ++matches > max_matches)
- clean_exit(0);
-
- if (match_after && keep_matching != match_after)
- keep_matching = match_after;
-
- return 1;
- }
-
- int blank_match_func(char *data, int len) {
- if (max_matches && ++matches > max_matches)
- clean_exit(0);
-
- return 1;
- }
-
-
- char *get_filter(char **argv) {
- char **arg = argv, *theirs, *mine;
- char *from, *to;
- int len = 0;
-
- if (!*arg)
- return NULL;
-
- while (*arg)
- len += strlen(*arg++) + 1;
-
- if (!(theirs = (char*)malloc(len + 1)) ||
- !(mine = (char*)malloc(len + sizeof(IP_ONLY))))
- return NULL;
-
- memset(theirs, 0, len + 1);
- memset(mine, 0, len + sizeof(IP_ONLY));
-
- arg = argv;
- to = theirs;
-
- while ((from = *arg++)) {
- while ((*to++ = *from++));
- *(to-1) = ' ';
- }
-
- sprintf(mine,IP_ONLY,theirs);
-
- free(theirs);
- return mine;
- }
-
-
- void clean_exit(int sig) {
- if (pattern.translate) free(pattern.translate);
- if (pattern.fastmap) free(pattern.fastmap);
-
- printf("exit\n");
- exit(0);
- }
-
-
- void usage(int e) {
- printf("usage: ngrep <-hViwqevxl> <-n num> <-d dev> <-A num> <regex> <pcap filter logic>\n");
- exit(e);
- }
-
-
- void version(void) {
- printf("ngrep: %s\n", rcsver);
- exit(0);
- }
-