Author Topic: basic Linux packet capture  (Read 1472 times)

0 Members and 1 Guest are viewing this topic.

Offline Xires

  • Noob Eater
  • Administrator
  • Knight
  • *
  • Posts: 379
  • Cookies: 149
    • View Profile
    • Feed The Trolls - Xires
basic Linux packet capture
« on: July 15, 2013, 10:44:15 am »
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'.


Code: (c) [Select]

/* 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)

-Xires

Offline Xires

  • Noob Eater
  • Administrator
  • Knight
  • *
  • Posts: 379
  • Cookies: 149
    • View Profile
    • Feed The Trolls - Xires
Re: basic Linux packet capture
« Reply #1 on: July 22, 2013, 09:13:04 am »
You'll need libpcap & development files for working with it.  Luckily, libpcap is actually likely to be installed on your machine as it's needed by nmap, tcpdump, wireshark, ettercap, etc.  The development files do need to be installed separately, usually.  Package name is probably called libpcap-dev.  Don't forget to specify the -lpcap to link with it.
-Xires