[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]

Communications Programming Concepts


Sample 2: Capturing Packet Data and Saving It to a File for Processing Later

The following code sample demonstrates capturing packet data and saving it to a file for processing. This sample is only for illustrating the use of the Packet Capture Library APIs. It is recommended that you write your own application for optimal function in a production environment.

/*
 * Use pcap_open_live() to open a packet capture device.
 * Use pcap_dump() to output the packet capture data in
 * binary format to a file for processing later.
 */
 
#include <unistd.h>
#include <stdio.h>
#include <pcap.h>
#include <netinet/in.h>
#include <sys/socket.h>
 
#define IFSZ 16
#define FLTRSZ 120
#define MAXHOSTSZ 256
#define PCAP_SAVEFILE "./pcap_savefile"
 
extern char *inet_ntoa();
 
int
usage(char *progname)
{
        printf("Usage: %s <interface> [<savefile name>]\n", basename(progname));
        exit(11);
}
 
int
main(int argc, char **argv)
{
        pcap_t *p;               /* packet capture descriptor */
        struct pcap_stat ps;     /* packet statistics */
        pcap_dumper_t *pd;       /* pointer to the dump file */
        char ifname[IFSZ];       /* interface name (such as "en0") */
        char filename[80];       /* name of savefile for dumping packet data */
        char errbuf[PCAP_ERRBUF_SIZE];  /* buffer to hold error text */
        char lhost[MAXHOSTSZ];   /* local host name */
        char fltstr[FLTRSZ];     /* bpf filter string */
        char prestr[80];         /* prefix string for errors from pcap_perror */
        struct bpf_program prog; /* compiled bpf filter program */
        int optimize = 1;        /* passed to pcap_compile to do optimization */
        int snaplen = 80;        /* amount of data per packet */
        int promisc = 0;         /* do not change mode; if in promiscuous */
                                 /* mode, stay in it, otherwise, do not */
        int to_ms = 1000;        /* timeout, in milliseconds */
        int count = 20;          /* number of packets to capture */
        u_int32 net = 0;         /* network IP address */
        u_int32 mask = 0;        /* network address mask */
        char netstr[INET_ADDRSTRLEN];   /* dotted decimal form of address */
        char maskstr[INET_ADDRSTRLEN];  /* dotted decimal form of net mask */
        int linktype = 0;        /* data link type */
        int pcount = 0;          /* number of packets actually read */
 
        /*
         * For this program, the interface name must be passed to it on the
         * command line. The savefile name may be optionally passed in
         * as well. If no savefile name is passed in, "./pcap_savefile" is
         * used. If there are no arguments, the program has been invoked
         * incorrectly.
         */
        if (argc < 2)
                usage(argv[0]);
 
        if (strlen(argv[1]) > IFSZ) {
                fprintf(stderr, "Invalid interface name.\n");
                exit(1);
        }
        strcpy(ifname, argv[1]);
 
        /*
         * If there is a second argument (the name of the savefile), save it in
         * filename. Otherwise, use the default name.
         */
        if (argc >= 3)
                strcpy(filename,argv[2]);
        else
                strcpy(filename, PCAP_SAVEFILE);
 
        /*
         * Open the network device for packet capture. This must be called
         * before any packets can be captured on the network device.
         */
        if (!(p = pcap_open_live(ifname, snaplen, promisc, to_ms, errbuf))) {
                fprintf(stderr, "Error opening interface %s: %s\n",
                        ifname, errbuf);
                exit(2);
        }
 
        /*
         * Look up the network address and subnet mask for the network device
         * returned by pcap_lookupdev(). The network mask will be used later 
         * in the call to pcap_compile().
         */
        if (pcap_lookupnet(ifname, &net, &mask, errbuf) < 0) {
                fprintf(stderr, "Error looking up network: %s\n", errbuf);
                exit(3);
        }
 
        /*
         * Create the filter and store it in the string called 'fltstr.'
         * Here, you want only incoming packets (destined for this host),
         * which use port 69 (tftp), and originate from a host on the
         * local network.
         */
 
        /* First, get the hostname of the local system */
        if (gethostname(lhost,sizeof(lhost)) < 0) {
                fprintf(stderr, "Error getting hostname.\n");
                exit(4);
        }
 
        /*
         * Second, get the dotted decimal representation of the network address
         * and netmask. These will be used as part of the filter string.
         */
        inet_ntop(AF_INET, (char*) &net, netstr, sizeof netstr);
        inet_ntop(AF_INET, (char*) &mask, maskstr, sizeof maskstr);
 
        /* Next, put the filter expression into the fltstr string. */
        sprintf(fltstr,"dst host %s and src net %s mask %s and udp port 69",
                lhost, netstr, maskstr);
 
        /*
         * Compile the filter. The filter will be converted from a text
         * string to a bpf program that can be used by the Berkely Packet
         * Filtering mechanism. The fourth argument, optimize, is set to 1 so
         * the resulting bpf program, prog, is compiled for better performance.
         */
        if (pcap_compile(p,&prog,fltstr,optimize,mask) < 0) {
                /*
                 * Print out appropriate text, followed by the error message
                 * generated by the packet capture library.
                 */
                fprintf(stderr, "Error compiling bpf filter on %s: %s\n",
                        ifname, pcap_geterr(p));
                exit(5);
        }
 
        /*
         * Load the compiled filter program into the packet capture device.
         * This causes the capture of the packets defined by the filter
         * program, prog, to begin.
         */
        if (pcap_setfilter(p, &prog) < 0) {
                /* Copy appropriate error text to prefix string, prestr */
                sprintf(prestr, "Error installing bpf filter on interface %s",
                        ifname);
                /*
                 * Print error to screen. The format will be the prefix string,
                 * created above, followed by the error message that the packet 
                 * capture library generates.
                 */
                pcap_perror(p,prestr);
                exit(6);
        }
 
        /*
         * Open dump device for writing packet capture data. In this sample,
         * the data will be written to a savefile. The name of the file is
         * passed in as the filename string.
         */
        if ((pd = pcap_dump_open(p,filename)) == NULL) {
                /*
                 * Print out error message if pcap_dump_open failed. This will
                 * be the below message followed by the pcap library error text,
                 * obtained by pcap_geterr().
                 */
                fprintf(stderr,
                        "Error opening savefile \"%s\" for writing: %s\n",
                        filename, pcap_geterr(p));
                exit(7);
        }
 
        /*
         * Call pcap_dispatch() to read and process a maximum of count (20)
         * packets. For each captured packet (a packet that matches the filter
         * specified to pcap_compile()), pcap_dump() will be called to write
         * the packet capture data (in binary format) to the savefile specified
         * to pcap_dump_open(). Note that packet in this case may not be a
         * complete packet. The amount of data captured per packet is
         * determined by the snaplen variable which is passed to
         * pcap_open_live().
         */
        if ((pcount = pcap_dispatch(p, count, &pcap_dump, (char *)pd)) < 0) {
                /*
                 * Print out appropriate text, followed by the error message
                 * generated by the packet capture library.
                 */
                sprintf(prestr,"Error reading packets from interface %s",
                        ifname);
                pcap_perror(p,prestr);
                exit(8);
        }
        printf("Packets received and successfully passed through filter: %d.\n",
                pcount);
 
        /*
         * Get and print the link layer type for the packet capture device,
         * which is the network device selected for packet capture.
         */
        if (!(linktype = pcap_datalink(p))) {
                fprintf(stderr,
                        "Error getting link layer type for interface %s",
                        ifname);
                exit(9);
        }
        printf("The link layer type for packet capture device %s is: %d.\n",
                ifname, linktype);
 
        /*
         * Get the packet capture statistics associated with this packet
         * capture device. The values represent packet statistics from the time
         * pcap_open_live() was called up until this call.
         */
        if (pcap_stats(p, &ps) != 0) {
                fprintf(stderr, "Error getting Packet Capture stats: %s\n",
                        pcap_geterr(p));
                exit(10);
        }
 
        /* Print the statistics out */
        printf("Packet Capture Statistics:\n");
        printf("%d packets received by filter\n", ps.ps_recv);
        printf("%d packets dropped by kernel\n", ps.ps_drop);
 
        /*
         * Close the savefile opened in pcap_dump_open().
         */
        pcap_dump_close(pd);
        /*
         * Close the packet capture device and free the memory used by the
         * packet capture descriptor.
         */     
        pcap_close(p);
}


[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]