////////////////////////////////////////////////////////////////////// // PPPTraf 1.0. (C) DiSKiLLeR, 9/2/2000. (diskiller@cnbinc.com) // // // // This program is distributed under the terms of the GNU License. // // Please refer to the file README and COPYING. // ////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include "bpf.h" #include "data.h" static int bpf_fd; static int bpf_buffsize; static int bpf_initted=0; // should be mutexed static int bpf_downstate=0; // needs to be mutexed static pthread_mutex_t mut; struct ip_hdr // My IP Packet header { short crap_a; short length; short ident; short crap_b; short crap_c; short checksum; long src_ip; long dest_ip; }; struct packet // First 44 interesting bytes { struct bpf_hdr bpf_hdr; // BPF header long ppp_hdr; // PPP header struct ip_hdr ip_hdr; // IP header // TCP header ... }; // Helper functions int bpf_open(); void bpf_process(struct packet); #define bhp ((struct bpf_hdr *)bp) // from TrafShow 2.0 // Used by trafshow's algorithm. int bpf_init(char *interface) { struct ifreq ifreq; int r; unsigned int dummy; pthread_mutex_lock(&mut); if(bpf_initted != 0) { pthread_mutex_unlock(&mut); return -1; } /** Get a bpf **/ bpf_fd = bpf_open(); /** Set kernel buffer size for 44 bytes. **/ //dummy = 44; /* Try and set the kernel buffer to something big. * It'll end up being 32k (seems to be the max it allows) * but its worth a try anyway ;) */ dummy = 1024*40; r = ioctl(bpf_fd, BIOCSBLEN, &dummy); if(r == -1) printf("[BIOCSBLEN] ret = %d\n", r); /** Select interface to listen to (tun0) **/ strcpy(ifreq.ifr_name, interface); r = ioctl(bpf_fd, BIOCSETIF, &ifreq); if(r == -1) printf("[BIOCSETIF] ret = %d\n", r); /* This isn't needed, because we're using threads at the moment. * If this is ever changed, we may need quicker response time (for * the ncurses display). */ /** Set immediate mode **/ //dummy = 1; //r = ioctl(bpf_fd, BIOCIMMEDIATE, &dummy); //if(r == -1) // printf("[BIOCIMMEDIATE] ret = %d\n", r); /* This is interesting, because the FBSD kernel lets us set it for * tun0 (and probably ppp) devices. But it doesn't make 'much' sense. * It wouldn't make much sense on ethernet devices either. (think * about what this program does/is for ...) */ /** Set promiscuous mode **/ //r = ioctl(bpf_fd, BIOCPROMISC); //if(r == -1) // printf("[BIOCPROMISC] ret = %d\n", r); /** Get buffer size **/ r = ioctl(bpf_fd, BIOCGBLEN, &bpf_buffsize); if(r == -1) printf("[BIOCGBLEN] ret = %d\n", r); bpf_initted = 1; pthread_mutex_unlock(&mut); return 0; } bpf_loop() { int r; struct packet pkt; char *buff=0; char *bp=0; int hdrlen, caplen, bplen=0; /** We haven't been init'd. **/ if(bpf_initted == 0) { return; } /** malloc some storage for our buffer **/ buff = (char *)malloc(bpf_buffsize+4); if(buff == NULL) { /** oops **/ fprintf(stderr, "bpf_loop: malloc() failed to allocate %d bytes.\n", bpf_buffsize+4); exit(1); } /** Main work loop **/ for(;;) { /** Check to see if we're asked to die. **/ if(bpf_downstate == 1) { pthread_mutex_lock(&mut); /** Do shutdown stuff **/ close(bpf_fd); free(buff); bpf_downstate = 2; pthread_mutex_unlock(&mut); pthread_exit(0); //die } // clear out packet // i don't think we really need this //memset(buff, '\0', bpf_buffsize); /** read in data from kernel (fetch a packet to process) **/ r = read(bpf_fd, buff, bpf_buffsize); /** Read no data? Lets switch context. Next time we're **/ /** scheduled, we'll try to read() again. **/ if(r == 0) { sleep(1); //usleep(1000000); continue; } /* This algorithm is responsible for the occasional coredump. * Its extremely rare, and i don't know why it happens. If * you find the cause, let me know. */ bplen = 0; /** Copied from trafshow. Nice algorithm :) **/ do { bp = buff + bplen; hdrlen = (int)bhp->bh_hdrlen; caplen = (int)bhp->bh_caplen; bplen += BPF_WORDALIGN(caplen + hdrlen); if(bplen>r) // processed! break; /** inefficient, i know, i know **/ memcpy(&pkt, bp, sizeof(pkt)); bpf_process(pkt); } while(bplen < r); } } int bpf_dropped() { struct bpf_stat stat; if(bpf_initted == 0) return -1; ioctl(bpf_fd, BIOCGSTATS, &stat); return stat.bs_drop; } int bpf_shutdown() { if(bpf_initted == 0) return 0; /** set downstate to 1. This 'asks' the bpf_loop thread to exit. **/ pthread_mutex_lock(&mut); bpf_downstate = 1; pthread_mutex_unlock(&mut); /** Wait for confirmation that bpf_loop thread is dead. **/ while(1) { pthread_mutex_lock(&mut); if(bpf_downstate == 2) break; pthread_mutex_unlock(&mut); usleep(1000); } pthread_mutex_unlock(&mut); return 0; } int bpf_open() { int fd; int n; char device[20]; for(n=0 ; n<16 ; n++) { /** Open /dev/bpf[0..15] **/ sprintf(device, "/dev/bpf%d", n); printf("Trying %s .... ", device); fd = open(device, O_RDONLY); /** Serious Error (not EBUSY) **/ if(fd == -1 && errno != EBUSY) { printf("fatal error.\n"); break; } /** Successful open **/ if(fd != -1) { printf("ok.\n"); break; } /** Its busy. Next bpf **/ printf("busy.\n"); } return( fd ); } void bpf_process(struct packet pkt) { struct in_addr in_addr; char src[20]; char dest[20]; short length; /** read out source IP **/ in_addr.s_addr = pkt.ip_hdr.src_ip; strcpy(src, (char *)inet_ntoa(in_addr.s_addr)); /** read out destination IP **/ in_addr.s_addr = pkt.ip_hdr.dest_ip; strcpy(dest, (char *)inet_ntoa(in_addr.s_addr)); /** read out the packet length **/ length = ntohs(pkt.ip_hdr.length); /** Store the data **/ data_store(src, dest, length); }