blob: 483f7a2052952105395916f5b5b9ec1759bfe2fc [file] [log] [blame]
/*
*
* gcc pcount.c -o pcount -lpcap
*
* VLAN support courtesy of Vincent Magnin <vincent.magnin@ci.unil.ch>
*
*/
#include <pcap/pcap.h>
#include <signal.h>
#include <sched.h>
#include <stdlib.h>
#define ALARM_SLEEP 1
#define DEFAULT_SNAPLEN 256
pcap_t *pd;
int verbose = 0;
struct pcap_stat pcapStats;
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/poll.h>
#include <time.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <net/ethernet.h> /* the L2 protocols */
static struct timeval startTime;
unsigned long long numPkts = 0, numBytes = 0;
#define DEFAULT_DEVICE "eth1" /* "e1000" */
int pcap_set_cluster(pcap_t *ring, u_int clusterId);
int pcap_set_application_name(pcap_t *handle, char *name);
char* pfring_format_numbers(double val, char *buf, u_int buf_len, u_int8_t add_decimals);
/* *************************************** */
/*
* The time difference in microseconds
*/
long delta_time (struct timeval * now,
struct timeval * before) {
time_t delta_seconds;
time_t delta_microseconds;
/*
* compute delta in second, 1/10's and 1/1000's second units
*/
delta_seconds = now -> tv_sec - before -> tv_sec;
delta_microseconds = now -> tv_usec - before -> tv_usec;
if(delta_microseconds < 0) {
/* manually carry a one from the seconds field */
delta_microseconds += 1000000; /* 1e6 */
-- delta_seconds;
}
return((delta_seconds * 1000000) + delta_microseconds);
}
/* ******************************** */
void print_stats() {
struct pcap_stat pcapStat;
struct timeval endTime;
float deltaSec;
static u_int64_t lastPkts = 0;
u_int64_t diff;
static struct timeval lastTime;
char buf1[64], buf2[64];
if(startTime.tv_sec == 0) {
lastTime.tv_sec = 0;
gettimeofday(&startTime, NULL);
return;
}
gettimeofday(&endTime, NULL);
deltaSec = (double)delta_time(&endTime, &startTime)/1000000;
if(pcap_stats(pd, &pcapStat) >= 0) {
fprintf(stderr, "=========================\n"
"Absolute Stats: [%u pkts rcvd][%u pkts dropped]\n"
"Total Pkts=%d/Dropped=%.1f %%\n",
pcapStat.ps_recv, pcapStat.ps_drop, pcapStat.ps_recv-pcapStat.ps_drop,
pcapStat.ps_recv == 0 ? 0 : (double)(pcapStat.ps_drop*100)/(double)pcapStat.ps_recv);
fprintf(stderr, "%llu pkts [%.1f pkt/sec] - %llu bytes [%.2f Mbit/sec]\n",
numPkts, (double)numPkts/deltaSec,
numBytes, (double)8*numBytes/(double)(deltaSec*1000000));
if(lastTime.tv_sec > 0) {
deltaSec = (double)delta_time(&endTime, &lastTime)/1000000;
diff = numPkts-lastPkts;
fprintf(stderr, "=========================\n"
"Actual Stats: %s pkts [%.1f ms][%s pkt/sec]\n",
pfring_format_numbers(diff, buf1, sizeof(buf1), 0), deltaSec*1000,
pfring_format_numbers(((double)diff/(double)(deltaSec)), buf2, sizeof(buf2), 1));
lastPkts = numPkts;
}
fprintf(stderr, "=========================\n");
}
lastTime.tv_sec = endTime.tv_sec, lastTime.tv_usec = endTime.tv_usec;
}
/* ******************************** */
void sigproc(int sig) {
static int called = 0;
if(called) return; else called = 1;
print_stats();
pcap_close(pd);
exit(0);
}
/* ******************************** */
void my_sigalarm(int sig) {
print_stats();
alarm(ALARM_SLEEP);
signal(SIGALRM, my_sigalarm);
}
/* ****************************************************** */
static char hex[] = "0123456789ABCDEF";
char* etheraddr_string(const u_char *ep, char *buf) {
u_int i, j;
char *cp;
cp = buf;
if ((j = *ep >> 4) != 0)
*cp++ = hex[j];
else
*cp++ = '0';
*cp++ = hex[*ep++ & 0xf];
for(i = 5; (int)--i >= 0;) {
*cp++ = ':';
if ((j = *ep >> 4) != 0)
*cp++ = hex[j];
else
*cp++ = '0';
*cp++ = hex[*ep++ & 0xf];
}
*cp = '\0';
return (buf);
}
/* ****************************************************** */
/*
* A faster replacement for inet_ntoa().
*/
char* _intoa(unsigned int addr, char* buf, u_short bufLen) {
char *cp, *retStr;
u_int byte;
int n;
cp = &buf[bufLen];
*--cp = '\0';
n = 4;
do {
byte = addr & 0xff;
*--cp = byte % 10 + '0';
byte /= 10;
if (byte > 0) {
*--cp = byte % 10 + '0';
byte /= 10;
if (byte > 0)
*--cp = byte + '0';
}
*--cp = '.';
addr >>= 8;
} while (--n > 0);
/* Convert the string to lowercase */
retStr = (char*)(cp+1);
return(retStr);
}
/* ************************************ */
char* intoa(unsigned int addr) {
static char buf[sizeof "ff:ff:ff:ff:ff:ff:255.255.255.255"];
return(_intoa(addr, buf, sizeof(buf)));
}
/* ************************************ */
inline char* in6toa(struct in6_addr addr6) {
static char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
snprintf(buf, sizeof(buf),
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
addr6.s6_addr[0], addr6.s6_addr[1], addr6.s6_addr[2],
addr6.s6_addr[3], addr6.s6_addr[4], addr6.s6_addr[5], addr6.s6_addr[6],
addr6.s6_addr[7], addr6.s6_addr[8], addr6.s6_addr[9], addr6.s6_addr[10],
addr6.s6_addr[11], addr6.s6_addr[12], addr6.s6_addr[13], addr6.s6_addr[14],
addr6.s6_addr[15]);
return(buf);
}
/* ****************************************************** */
char* proto2str(u_short proto) {
static char protoName[8];
switch(proto) {
case IPPROTO_TCP: return("TCP");
case IPPROTO_UDP: return("UDP");
case IPPROTO_ICMP: return("ICMP");
default:
snprintf(protoName, sizeof(protoName), "%d", proto);
return(protoName);
}
}
/* ****************************************************** */
static int32_t thiszone;
void dummyProcesssPacket(u_char *_deviceId,
const struct pcap_pkthdr *h,
const u_char *p) {
// printf("pcap_sendpacket returned %d\n", pcap_sendpacket(pd, p, h->caplen));
if(verbose) {
struct ether_header ehdr;
u_short eth_type, vlan_id;
char buf1[32], buf2[32];
struct ip ip;
struct ip6_hdr ip6;
int s = (h->ts.tv_sec + thiszone) % 86400;
printf("%02d:%02d:%02d.%06u ",
s / 3600, (s % 3600) / 60, s % 60,
(unsigned)h->ts.tv_usec);
memcpy(&ehdr, p, sizeof(struct ether_header));
eth_type = ntohs(ehdr.ether_type);
printf("[%s -> %s] ",
etheraddr_string(ehdr.ether_shost, buf1),
etheraddr_string(ehdr.ether_dhost, buf2));
if(eth_type == 0x8100) {
vlan_id = (p[14] & 15)*256 + p[15];
eth_type = (p[16])*256 + p[17];
printf("[vlan %u] ", vlan_id);
p+=4;
}
if(eth_type == 0x0800) {
memcpy(&ip, p+sizeof(ehdr), sizeof(struct ip));
printf("[%s]", proto2str(ip.ip_p));
printf("[%s ", intoa(ntohl(ip.ip_src.s_addr)));
printf("-> %s] ", intoa(ntohl(ip.ip_dst.s_addr)));
} else if(eth_type == 0x86DD) {
memcpy(&ip6, p+sizeof(ehdr), sizeof(struct ip6_hdr));
printf("[%s ", in6toa(ip6.ip6_src));
printf("-> %s] ", in6toa(ip6.ip6_dst));
} else if(eth_type == 0x0806)
printf("[ARP]");
else
printf("[eth_type=0x%04X]", eth_type);
printf("[caplen=%u][len=%u]\n", h->caplen, h->len);
}
if(numPkts == 0) gettimeofday(&startTime, NULL);
numPkts++, numBytes += h->len;
if(verbose == 2) {
int i;
for(i = 0; i < h->caplen; i++)
printf("%02X ", p[i]);
printf("\n");
}
}
/* *************************************** */
int32_t gmt2local(time_t t) {
int dt, dir;
struct tm *gmt, *loc;
struct tm sgmt;
if (t == 0)
t = time(NULL);
gmt = &sgmt;
*gmt = *gmtime(&t);
loc = localtime(&t);
dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
(loc->tm_min - gmt->tm_min) * 60;
/*
* If the year or julian day is different, we span 00:00 GMT
* and must add or subtract a day. Check the year first to
* avoid problems when the julian day wraps.
*/
dir = loc->tm_year - gmt->tm_year;
if (dir == 0)
dir = loc->tm_yday - gmt->tm_yday;
dt += dir * 24 * 60 * 60;
return (dt);
}
/* *************************************** */
void printHelp(void) {
char errbuf[PCAP_ERRBUF_SIZE];
pcap_if_t *devpointer;
printf("pcount\n(C) 2003-13 Deri Luca <deri@ntop.org>\n");
printf("-h [Print help]\n");
printf("-i <device> [Device name]\n");
printf("-f <filter> [pcap filter]\n");
printf("-l <len> [Capture length]\n");
printf("-S [Do not strip hw timestamps (if present)]\n");
printf("-v <mode> [Verbose [1: verbose, 2: very verbose (print packet payload)]]\n");
if(pcap_findalldevs(&devpointer, errbuf) == 0) {
int i = 0;
printf("\nAvailable devices (-i):\n");
while(devpointer) {
printf(" %d. %s\n", i++, devpointer->name);
devpointer = devpointer->next;
}
}
}
/* *************************************** */
int main(int argc, char* argv[]) {
char *device = NULL, c, *bpfFilter = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
int promisc, snaplen = DEFAULT_SNAPLEN;;
struct bpf_program fcode;
u_int8_t dont_strip_hw_ts = 0;
#if 0
struct sched_param schedparam;
schedparam.sched_priority = 99;
if(sched_setscheduler(0, SCHED_FIFO, &schedparam) == -1) {
printf("error while setting the scheduler, errno=%i\n",errno);
exit(1);
}
mlockall(MCL_CURRENT|MCL_FUTURE);
#define TEST_PROCESSOR_AFFINITY
#ifdef TEST_PROCESSOR_AFFINITY
{
unsigned long new_mask = 1;
unsigned int len = sizeof(new_mask);
unsigned long cur_mask;
pid_t p = 0; /* current process */
int ret;
ret = sched_getaffinity(p, len, NULL);
printf(" sched_getaffinity = %d, len = %u\n", ret, len);
ret = sched_getaffinity(p, len, &cur_mask);
printf(" sched_getaffinity = %d, cur_mask = %08lx\n", ret, cur_mask);
ret = sched_setaffinity(p, len, &new_mask);
printf(" sched_setaffinity = %d, new_mask = %08lx\n", ret, new_mask);
ret = sched_getaffinity(p, len, &cur_mask);
printf(" sched_getaffinity = %d, cur_mask = %08lx\n", ret, cur_mask);
}
#endif
#endif
startTime.tv_sec = 0;
thiszone = gmt2local(0);
while((c = getopt(argc,argv,"hi:l:v:f:S")) != '?') {
if((c == 255) || (c == -1)) break;
switch(c) {
case 'h':
printHelp();
exit(0);
break;
case 'i':
device = strdup(optarg);
break;
case 'l':
snaplen = atoi(optarg);
break;
case 'v':
verbose = atoi(optarg);
break;
case 'f':
bpfFilter = strdup(optarg);
break;
case 'S':
dont_strip_hw_ts = 1;
break;
}
}
if(device == NULL) {
if((device = pcap_lookupdev(errbuf)) == NULL) {
printf("pcap_lookup: %s", errbuf);
return(-1);
}
}
if(!dont_strip_hw_ts) setenv("PCAP_PF_RING_STRIP_HW_TIMESTAMP", "1", 1);
printf("Capturing from %s\n", device);
/* hardcode: promisc=1, to_ms=500 */
promisc = 1;
if((pd = pcap_open_live(device, snaplen,
promisc, 500, errbuf)) == NULL) {
printf("pcap_open_live: %s\n", errbuf);
return(-1);
}
if(bpfFilter != NULL) {
if(pcap_compile(pd, &fcode, bpfFilter, 1, 0xFFFFFF00) < 0) {
printf("pcap_compile error: '%s'\n", pcap_geterr(pd));
} else {
if(pcap_setfilter(pd, &fcode) < 0) {
printf("pcap_setfilter error: '%s'\n", pcap_geterr(pd));
}
}
}
pcap_set_application_name(pd, "pcount");
signal(SIGINT, sigproc);
if(!verbose) {
signal(SIGALRM, my_sigalarm);
alarm(ALARM_SLEEP);
}
pcap_set_watermark(pd, 128);
pcap_loop(pd, -1, dummyProcesssPacket, NULL);
pcap_close(pd);
return(0);
}