//////////////////////////////////////////////////////////////////////
// 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 <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <pthread.h>
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1