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

# Opening an adapter and capturing the packets
[WinPcap tutorial: a step by step guide to program WinPcap]

Now that we've seen how to obtain an adapter to play with, let's start the real job, opening the device and capturing the some traffic. In this lesson we'll write a program that will print some information for each packet flowing through the network.

The function that opens a capture device is pcap_open(). Among its parameters, snaplen, flags and to_ms deserve a better explanation.

snaplen specifies the portion of the packet to capture. On some OSes (like xBSD and Win32), the packet driver gives the possibility to capture only the initial part of any packet: this decreases the amount of data to copy and therefore improves the efficiency of the capture. In this case we use a value (65536) higher than the greatest MTU that we could encounter, therefore we make sure that the application will always receive the whole packet.

flags: the most important flag is the one that indicates if the adapter will be put in promiscuous mode. In normal situations, an adapter extracts from the network only the traffic destined to it; the packets exchanged by other hosts are therefore ignored. Instead, when the adapter is in promiscuous mode it accepts the whole traffic: this means that on shared media (like non-switched Ethernet) WinPcap will be able to capture the packets of other hosts as well (provided that your network card is receiving them, e.g. you are not on a switched network). Promiscuous mode is the default for most capture applications, so we enable it in the following example.

to_ms specifies the read timeout, in milliseconds. A read on the adapter (for example with pcap_dispatch() or pcap_next_ex()) will always return after to_ms milliseconds, even if no packets are available from the network. Moreover, to_ms defines the interval between statistical report if the adapter is in statistical mode (see the lesson "Gathering Statistics on the network traffic " for information about statistical mode). Setting to_ms to 0 means no timeout, a read on the adapter never returns if no packets arrive. A -1 timeout on the other side causes a read on the adapter to always return immediately.

    #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()
    {
    pcap_if_t *alldevs;
    pcap_if_t *d;
    int inum;
    int i=0;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];

        /* Retrieve the device list on the local machine */
        if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &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 device */
        if ( (adhandle= pcap_open(d->name,          // name of the device
                                  65536,            // portion of the packet to capture
                                                    // 65536 guarantees that the whole packet will be captured on all the link layers
                                  PCAP_OPENFLAG_PROMISCUOUS,    // promiscuous mode
                                  1000,             // read timeout
                                  NULL,             // authentication on the remote machine
                                  errbuf            // error buffer
                                  ) ) == NULL)
        {
            fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
            /* Free the device list */
            pcap_freealldevs(alldevs);
            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, NULL);

        return 0;
    }

    /* Callback function invoked by libpcap for every incoming packet */
    void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
    {
        struct tm *ltime;
        char timestr[16];

        /* convert the timestamp to readable format */
        ltime=localtime(&header->ts.tv_sec);
        strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);

        printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);

    }

Once the adapter is opened, the capture can be started with pcap_dispatch() or pcap_loop(). These two functions are very similar, the difference is that pcap_ dispatch() is granted to return when the expires while pcap_loop() doesn't return until cnt packets have been captured, so it can block for an arbitrary period on an under-utilized network. pcap_loop() is enough for the purpose of this sample, while pcap_dispatch() is normally used in more complex program.

Both these functions have a callback parameter, pointing to a function that will receive the packets, packet_handler in this case. This function is invoked by libpcap for every new packet coming from the network and receives a generic status (corresponding to the user parameter of pcap_loop() and pcap_dispatch()), an header with some information on the packet like the timestamp and the length, and finally the actual data of the packet including all the protocol headers. Note that the MAC CRC is normally not present, because it is removed by the network adapter after frame validation. Note also that most adapters discard the packets with wrong CRC, therefore WinPcap is normally not able to capture them.

The just proposed example extracts the timestamp and the length of every packet from the pcap_pkthdr header and prints them on the screen.

Please note that using pcap_loop() could have some drawback, mostly related to the fact that the dispatcher handler is called by the packet capture driver; therefore the user application does not have control on it. To solve this problem (and to have simpler and more readable programs), we suggest using the pcap_next_ex(), which is presented in the next example (Capturing the packets without the callback ).

<<< Previous Next >>>

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