This is a little piece of test code that I'd created a while ago for work stuff. I went through and commented a bunch of stuff but if anyone has questions, feel free to ask. Note that this is not exactly 'noob-friendly'.
/* cap-test.c - v1.4 : 2013-07-15 - Xires <xires012@gmail.com>
*
* COMPILE: gcc -Wall -Wextra -W -o cap-test{,.c} -pthread -lpcap
*
* RUN:
* ./cap-test <num> [dev]
* num = number of packets to capture
* dev = device upon which to listen
*
* NOTE:
* -ansi or -std=c99 cannot be used because of pcap
* -pedantic cannot be used because of the variadic macros 'pout' & 'perr'
*
* To run this as non-root user, set cap_net_raw:
* # setcap cap_net_raw=pe ./cap-test.c
*
* Capabilities must be set after every compile.
*
*/
#include <stdio.h> /* fprintf */
#include <stdlib.h> /* u_char, u_int, etc. for pcap */
#include <time.h> /* localtime_r & other time-related stuff */
#include <pthread.h> /* pthread_create & other thread-related stuff */
#include <pcap.h> /* packet capturing library */
#define DEBUG 0 /* basic debugging by bitwise flag check */
/* Macros to simplify output operations */
#define pout(f, ...) fprintf(stdout, f, ## __VA_ARGS__)
#define perr(f, ...) fprintf(stderr, f, ## __VA_ARGS__)
typedef struct capargs_s { /* struct to hold our arguments to capture() */
int cnt; /* number of packets to capture */
char *dev; /* device from which to capture packets */
} capargs_t, ca_t; /* 2 different typenames for better code beauty */
void* capture(void*);
void handler(unsigned char*, const struct pcap_pkthdr*, const unsigned char*);
void prn_byts(const unsigned char*, unsigned int);
int main(int argc, char **argv) {
pthread_t c; /* represents our capture thread */
capargs_t d; /* holds arguments to pass to capture thread */
unsigned int j; /* holds return value from pthread_join */
void *r; /* holds return value from capture thread */
if ((argc < 2) || (argc > 3)) return 1; /* 1 or 2 arguments required */
else if (argc == 3) d.dev = argv[2]; /* if 2, 2nd is device name */
else d.dev = NULL; /* or look for device later */
d.cnt = atoi(argv[1]); /* packet capture count */
pthread_create(&c, NULL, capture, &d); /* create thread */
if ((j = pthread_join(c, &r))) return j; /* wait for thread to finish */
j = *((unsigned int*) &r); /* reuse for similar purpose */
return j; /* return threads return val */
}
void* capture(void *d) { /* does our capturing */
char ebuf[PCAP_ERRBUF_SIZE]; /* holds errors returned by pcap calls */
pcap_t *pcp; /* pointer to packet capture instance */
ca_t args = *((ca_t*) d); /* fetch argument struct */
if (!args.dev) /* if no device.. */
if (!(args.dev = pcap_lookupdev(ebuf))) /* search for one.. */
return (perr("pcap_lookupdev(): %s\n", ebuf), (void*) 2); /* or die */
#if (DEBUG & 1)
pout("dev: %s\n", args.dev);
#endif
/* try to open the device; die if we can't */
if (!(pcp = pcap_open_live(args.dev, BUFSIZ, 1, 1000, ebuf)))
return (perr("pcap_open_live(): %s\n", ebuf), (void*) 3);
while (args.cnt--) /* as long as we still haven't reached our goal.. */
pcap_dispatch(pcp, 1, (pcap_handler) handler, NULL); /* get pkt */
return NULL; /* we're done */
}
void handler(unsigned char *u, const struct pcap_pkthdr *h, const unsigned char *b) {
static struct tm t; /* holds our calculated time */
static char tim[20], out[28]; /* buffers for readable time */
(void)(u); /* we have no use for 'u'; shut the compiler up */
/* translate packet arrival time from timeval to struct tm */
localtime_r(&h->ts.tv_sec, &t);
strftime(tim, sizeof(tim), "%Y.%m.%d@%H:%M:%S", &t); /* make readable */
snprintf(out, sizeof(out), "%s.%06d", tim, (int) h->ts.tv_usec); /* done */
pout("%s", out); /* print out the now readable arrival time */
#if (DEBUG & 1)
pout("\tcaplen: %d\tlen: %d", h->caplen, h->len);
#endif
prn_byts(b, h->caplen); /* print a selection of captured bytes */
fflush(stdout); /* flush the output stream */
return;
}
void prn_byts(const unsigned char *b, unsigned int l) {
register unsigned int i = 0; /* iterator */
if (l > 120) l = 120; /* only print out, at max, the first 120 bytes */
while (i < l) {
if (!(i++ % 24)) pout("\n\t"); /* new line every 24 bytes output */
pout("%02x ", b[i]); /* print out the current byte */
}
pout("\n"); /* newline coherency */
return; /* done; return to calling process (handler) */
}
(sorry for the extra blank lines; the forum 'code' tags seem to be doing it; will look into a fix at some point)