Main Page Modules Data Structures File List Data Fields Globals Related Pages

# Handling offline dump files
[WinPcap tutorial: a step by step guide to program WinPcap]

In the previous lessons we became experts in packet capture from network cards, now we're going to learn how to handle packet dumps. WinPcap offers a wide range of functions to save the network traffic to a file and to read the content of dumps; this lesson will teach how to use all these functions. We'll see also how to use the kernel dump feature of WinPcap to obtain high-performance dumps.

The file format is the libpcap one. This format, very simple, contains the data of the captured packets in binary form and is a standard used by a lot of network tools like for example WinDump, Ethereal and Snort.

Saving packets to a dump file

First of all, let's see how to write packets in libpcap format.

The following example captures the packets from the selected interface and saves them on a file whose name is provided by the user.

    #include "pcap.h"

    /* prototype of the packet handler */
    void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

    main(int argc, char **argv)
    {
        pcap_if_t *alldevs;
        pcap_if_t *d;
        int inum;
        int i=0;
        pcap_t *adhandle;
        char errbuf[PCAP_ERRBUF_SIZE];
        pcap_dumper_t *dumpfile;

        /* Check command line */
        if(argc != 2){

            printf("usage: %s filename", argv[0]);
            return -1;

        }

        /* Retrieve the device list */
        if (pcap_findalldevs(&alldevs, errbuf) == -1)
        {
            fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
            exit(1);
        }

        /* Print the list */
        for(d=alldevs; d; d=d->next)
        {
            printf("%d. %s", ++i, d->name);
            if (d->description)
                printf(" (%s)\n", d->description);
            else
                printf(" (No description available)\n");
        }

        if(i==0)
        {
            printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
            return -1;
        }

        printf("Enter the interface number (1-%d):",i);
        scanf("%d", &inum);

        if(inum < 1 || inum > i)
        {
            printf("\nInterface number out of range.\n");
            /* Free the device list */
            pcap_freealldevs(alldevs);
            return -1;
        }

        /* Jump to the selected adapter */
        for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);

        /* Open the adapter */
        if ( (adhandle = pcap_open_live(d->name, // name of the device
                                 65536,     // portion of the packet to capture.
                                            // 65536 grants that the whole packet will be captured on all the MACs.
                                 1,         // promiscuous mode
                                 1000,      // read timeout
                                 errbuf     // error buffer
                                 ) ) == NULL)
        {
            fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
            /* Free the device list */
            pcap_freealldevs(alldevs);
            return -1;
        }

        /* Open the dump file */
        dumpfile = pcap_dump_open(adhandle, argv[1]);
        if(dumpfile==NULL){
            fprintf(stderr,"\nError opening output file\n");
            return -1;
        }

        printf("\nlistening on %s...\n", d->description);

        /* At this point, we don't need any more the device list. Free it */
        pcap_freealldevs(alldevs);

        /* start the capture */
        pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);

        return 0;
    }

    /* Callback function invoked by libpcap for every incoming packet */
    void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data)
    {
        /* save the packet on the dump file */
        pcap_dump(dumpfile, header, pkt_data);
    }

As you can see, the structure of the program is very similar to the ones seen in the previous lessons. The differences are:

- a call to pcap_dump_open() is issued once the interface is opened. This call opens a dump file and associates it with the interface.
- the packets are written to this file with a pcap_dump() inside the packet_handler() callback. The parameters of this function are the same received by the pcap_handler(), so saving a packet is very simple.

Reading packets from a dump file

Now that we have a dump file available, we can see how to read its content. The following code opens a libpcap dump and displays every packet contained in it. The file is opened with pcap_open_offline(), then the usual pcap_loop() is used to cycle among the packets. As you can see, reading packets from an offline capture is nearly identical to receiving them from a physical interface.

    #include <stdio.h>
    #include <pcap.h>

    #define LINE_LEN 16

    void dispatcher_handler(u_char *, const struct pcap_pkthdr *, const u_char *);

    main(int argc, char **argv) {

        pcap_t *fp;
        char errbuf[PCAP_ERRBUF_SIZE];

        if(argc != 2){

            printf("usage: %s filename", argv[0]);
            return -1;

        }

        /* Open a capture file */
        if ( (fp = pcap_open_offline(argv[1], errbuf) ) == NULL)
        {
            fprintf(stderr,"\nError opening dump file\n");
            return -1;
        }

        // read and dispatch packets until EOF is reached
        pcap_loop(fp, 0, dispatcher_handler, NULL);

        return 0;
    }

    void dispatcher_handler(u_char *temp1,
                            const struct pcap_pkthdr *header, const u_char *pkt_data)
    {
        u_int i=0;

        /* print pkt timestamp and pkt len */
        printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len);

        /* Print the packet */
        for (i=1; (i < header->caplen + 1 ) ; i++)
        {
            printf("%.2x ", pkt_data[i-1]);
            if ( (i % LINE_LEN) == 0) printf("\n");
        }

        printf("\n\n");

    }

The following example has the same purpose of the last one, but pcap_next_ex() is used instead of the pcap_loop() callback method.

    #include <stdio.h>
    #include <pcap.h>

    #define LINE_LEN 16

    main(int argc, char **argv) {

        pcap_t *fp;
        char errbuf[PCAP_ERRBUF_SIZE];
        struct pcap_pkthdr *header;
        u_char *pkt_data;
        u_int i=0;
        int res;

        if(argc != 2){

            printf("usage: %s filename", argv[0]);
            return -1;

        }

        /* Open a capture file */
        if ( (fp = pcap_open_offline(argv[1], errbuf) ) == NULL)
        {
            fprintf(stderr,"\nError opening dump file\n");
            return -1;
        }

        /* Retrieve the packets from the file */
        while((res = pcap_next_ex( fp, &header, &pkt_data)) >= 0){
            /* print pkt timestamp and pkt len */
            printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len);

            /* Print the packet */
            for (i=1; (i < header->caplen + 1 ) ; i++)
            {
                printf("%.2x ", pkt_data[i-1]);
                if ( (i % LINE_LEN) == 0) printf("\n");
            }

            printf("\n\n");
        }

        if(res == -1){
            printf("Error reading the packets: %s\n", pcap_geterr(fp));
        }

        return 0;
    }

Writing packets to a dump file with pcap_live_dump

Recent versions of WinPcap provide a further way to save network traffic to disk, the pcap_live_dump() function. pcap_live_dump() takes three parameters: a file name, the maximum size (in bytes) that this file is allowed to reach and the maximum amount of packets that the file is allowed to contain. Zero means no limit for both these values. Notice that the program can set a filter (with pcap_setfilter(), see the tutorial Filtering the traffic ) before calling pcap_live_dump() to define the subset of the traffic that will be saved.

pcap_live_dump() is non-blocking, therefore it starts the dump and returns immediately: The dump process goes on asynchronously until the maximum file size or the maximum amount of packets has been reached.

The application can wait or check the end of the dump with pcap_live_dump_ended(). Beware that if the sync parameter is nonzero this function will block your application forever if the limits are both 0.

The difference between pcap_live_dump() and pcap_dump(), apart from the possibility to set limits, is performance. pcap_live_dump() exploits the ability of the WinPcap NPF driver (see NPF driver internals manual ) to write dumps from kernel level, minimizing the number of context switches and memory copies.

Obviously, since this feature is currently not available on other operating systems, pcap_live_dump() is WinPcap specific and is present only under Win32.

documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.