Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Introduction to the WinPcap Networking Libraries

4.33/5 (22 votes)
18 Oct 2008CPOL6 min read 1  
An introduction to the WinPcap networking libraries.

Motivation

The first question you should ask yourself before starting to write an article is why do you need to write it. In my case, I have decided to write this introductory article because I saw that many people are interested in networking and they want to use the WinPcap library for programming.

WinPcap is a powerful set of libraries which can be used for various tasks, very important in network programming: obtain all available network adapters, obtain information about an adapter, like the name and the description of the adapter, capture network packets using one of the network interface cards of the computer, send network packets across the network, or filter the captured packets, to obtain only the desired ones.

Introduction

The most important thing to do before using this library is to install it correctly. That’s why I have decided to give a helping hand to all people who want to install and use the WinPcap library. Remember this is not a WinPcap tutorial. This presents the quickest way to install and start using WinPcap. Thus, let’s start by learning how to install WinPcap.

Installing and configuring WinPcap

First of all, we must install the WinPcap driver and the DLL components. The latest version is 4.0.2. You can get it from the following location: http://www.winpcap.org/install/default.htm.

Sample Image

After downloading and running the executable file, following the instructions given by the wizard, the WinPcap components are installed on your computer.

Sample Image

The next step is to download the WinPcap developer’s pack. This can be obtained from the following location: http://www.winpcap.org/devel.htm.

Sample Image

This is a Zip file that contains the resources needed to create WinPcap networking applications: libraries, include files, documentation, and example applications. You must download the Zip file and uncompress it to the desired folder. For example, I have placed the developer’s pack in “C:\WpdPack_4_0_2\WpdPack”.

Sample Image

Now, we are finally ready to start using WinPcap’s power to develop strong, networking applications. For the sake of the example, I will use Visual Studio 2005 in the following examples.

Let’s see how to link a C++ program with the WinPcap libraries. First, we create a simple C++ console application project, named winpcapTest. Then, go to Project -> winpcapTest Properties… and do the following:

Under the “Configuration Properties -> C/C++ -> General” tab, add the WinPcap include path (“C:\WpdPack_4_0_2\WpdPack\Include”) to Additional Include Directories:

Sample Image

Under the “Configuration Properties -> Linker -> General” tab, add the WinPcap library path (“C:\WpdPack_4_0_2\WpdPack\Lib”) to Additional Library Directories:

Sample Image

Under the “Configuration Properties -> Linker -> Input” tab, add the two main WinPcap libraries (wpcap.lib and Packet.lib) to Additional Dependencies:

Sample Image

That’s all there is to it. Now, we are ready to test the WinPcap networking library.

In what follows, we will present some simple examples of applications that use the WinPcap libraries. For more detailed tutorials, see the WinPcap documentation materials.

Using WinPcap

To use the libraries, we must simply include the WinPcap header (#include <pcap.h>) at the beginning of every source file that uses the libraries. Also, usually we intend to use WinPcap remote capabilities. In this case, we must add HAVE_REMOTE to the preprocessor definitions. To do this, under the “Project -> winpcapTest Properties… -> Configuration Properties -> C/C++ -> Preprocessor” tab, add the HAVE_REMOTE definition to Preprocessor Definitions:

Sample Image

Obtaining the adapter list

Typically, the first thing we do when we use a WinPcap based application is to obtain the list of attached network adapters. We do this with the pcap_findalldevs_ex() function, which returns a linked list of pcap_if structures. Every pcap_if structure contains detailed information about a network adapter. In particular, name and description contain the name and a detailed description of the corresponding device.

In the following code, we obtain the network adapters and we print it on the screen. If no adapters are found, we print an error.

C++
#include <pcap.h>

int _tmain(int argc, _TCHAR* argv[])
{
    pcap_if_t * allAdapters;
    pcap_if_t * adapter;
    char errorBuffer[ PCAP_ERRBUF_SIZE ];

    // retrieve the adapters from the computer
    if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, 
                &allAdapters, errorBuffer ) == -1 )
    {
        fprintf( stderr, "Error in pcap_findalldevs_ex function: %s\n", 
                 errorBuffer );
        return -1;
    }

    // if there are no adapters, print an error
    if( allAdapters == NULL )
    {
        printf( "\nNo adapters found! Make sure WinPcap is installed.\n" );
        return 0;
    }

    // print the list of adapters along with basic information about an adapter
    int crtAdapter = 0;
    for( adapter = allAdapters; adapter != NULL; adapter = adapter->next)
    {
        printf( "\n%d.%s ", ++crtAdapter, adapter->name );
        printf( "-- %s\n", adapter->description );
    }

    printf( "\n" );

    // free the adapter list
    pcap_freealldevs( allAdapters );

    system( "PAUSE" );
    return 0;
}

In the code above, we see that the pcap_findalldevs_ex() function has an errorBuffer parameter. If an error is encountered, the description of the error will be stored in this parameter. At the end, to avoid memory leaks, we must free the adapter list, since we don’t need it anymore.

If we compile the above program on an XP machine, we get the following adapters:

  1. rpcap://\Device\NPF_GenericDialupAdapter -- Network adapter 'Adapter for generic dialup and VPN capture' on local host
  2. rpcap://\Device\NPF_{E5C91E92-0E7F-4286-BDC3-4A6547E099C1} -- Network adapter 'VIA Rhine II Fast Ethernet Adapter (Microsoft's Packet Scheduler)' on local host

Opening an adapter and capturing the packets

Once we have learned how to obtain the list of attached adapters, it is time to see how to open a specified adapter and capture some packets. We use the function pcap_open() to open an adapter. Three of the parameters passed to pcap_open() are named snaplen, flags, and to_ms.

  • snaplen specifies the length of the packet to capture. For instance, on a Windows OS, the adapter can be configured to capture only a specified part of every network packet. To enable the application to always receive the entire contents of a packet, we give this parameter a value 65536.
  • flags specifies all flags passed to the adapter. The most important flag is the one that specifies if the adapter will be in promiscuous mode. If not in promiscuous mode, the adapter captures only the packets destined to it. The other packets are ignored. In promiscuous mode, the adapter captures all network packets (destined to it or not).
  • to_ms specifies the read timeout, in milliseconds. This means that, after to_ms milliseconds, the capture session will exit on the adapter. Setting this value to 0 means that we do not want a timeout.

The following program opens a capture session on an adapter and prints some information about each captured network packet:

C++
#include <pcap.h>

int _tmain(int argc, _TCHAR* argv[])
{
    pcap_if_t           * allAdapters;
    pcap_if_t           * adapter;
    pcap_t           * adapterHandle;
    struct pcap_pkthdr * packetHeader;
    const u_char       * packetData;
    char                 errorBuffer[ PCAP_ERRBUF_SIZE ];

    // retrieve the adapters from the computer
    if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, 
            &allAdapters, errorBuffer ) == -1 )
    {
        fprintf( stderr, "Error in pcap_findalldevs_ex function: %s\n", errorBuffer );
        return -1;
    }

    // if there are no adapters, print an error
    if( allAdapters == NULL )
    {
    printf( "\nNo adapters found! Make sure WinPcap is installed.\n" );
        return 0;
    }

    // print the list of adapters along with basic information about an adapter
    int crtAdapter = 0;
    for( adapter = allAdapters; adapter != NULL; adapter = adapter->next)
    {
    printf( "\n%d.%s ", ++crtAdapter, adapter->name );
    printf( "-- %s\n", adapter->description );
    }

    printf( "\n" );

    int adapterNumber;

    printf( "Enter the adapter number between 1 and %d:", crtAdapter );
    scanf_s( "%d", &adapterNumber );
    
    if( adapterNumber < 1 || adapterNumber > crtAdapter )
    {
        printf( "\nAdapter number out of range.\n" );

        // Free the adapter list
        pcap_freealldevs( allAdapters );

        return -1;
    }
    
    // parse the list until we reach the desired adapter
    adapter = allAdapters;
    for( crtAdapter = 0; crtAdapter < adapterNumber - 1; crtAdapter++ )
    adapter = adapter->next;

    // open the adapter
    adapterHandle = pcap_open( adapter->name, // name of the adapter
                               65536,         // portion of the packet to capture
                                              // 65536 guarantees that the whole 
                                              // packet will be captured
                               PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
                               1000,             // read timeout - 1 millisecond
                               NULL,          // authentication on the remote machine
                               errorBuffer    // error buffer
                              );

    if( adapterHandle == NULL )
    {
        fprintf( stderr, "\nUnable to open the adapter\n", adapter->name );

        // Free the adapter list
        pcap_freealldevs( allAdapters );

        return -1;
    }
    
    printf( "\nCapture session started on  adapter %s...\n", adapter->name );

    // free the adapter list
    pcap_freealldevs( allAdapters );


    // this is the most important part of the application
    // here we start receiving packet traffic
    int retValue;
    while( ( retValue = pcap_next_ex( adapterHandle, 
                      &packetHeader, 
                      &packetData ) ) >= 0 )
    {
    // timeout elapsed if we reach this point
    if( retValue == 0 )
            continue;
        
    // we print some information about the captured packet
    // we print only the length of the packet here
    printf( "length of packet: %d\n", packetHeader->len );
    }
    
    // if we get here, there was an error reading the packets
    if( retValue == -1 )
    {
        printf( "Error reading the packets: %s\n", pcap_geterr( adapterHandle ) );
        return -1;
    }

    system( "PAUSE" );
    return 0;
}

Some explanations are in order about the above program.

First of all, we see that the pcap_open() function, after opening the adapter, returns a handle to an adapter handle (a pcap_t structure), which we will use intensively in the capture session.

For capturing a packet, we use the pcap_next_ex() function. This function receives as parameters the adapter handle created with the call to the pcap_open() function, a pointer to a pcap_pkthdr structure, which holds some information about the packet header, and a pointer to a buffer in which we will store the whole packet data (including the packet header).

Sending packets over the network

Another useful feature of the WinPcap libraries is the ability to send packets over the network.

To send a packet, we use the pcap_sendpacket() function. This function receives as parameters a buffer containing the data to send, the length of the buffer, and the adapter handle. An important thing to notice here is that, in order to send meaningful packets on the network, we must correctly create the packet data (with respect to the internet protocol headers).

In what follows, we create a simple program that sends a packet over the network:

C++
#include <pcap.h>

int _tmain(int argc, _TCHAR* argv[])
{
    pcap_if_t      * allAdapters;
    pcap_if_t       * adapter;
    pcap_t       * adapterHandle;
    u_char         packet[ 20 ];
    char             errorBuffer[ PCAP_ERRBUF_SIZE ];

    // retrieve the adapters from the computer
    if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, 
                &allAdapters, errorBuffer ) == -1 )
    {
        fprintf( stderr, "Error in pcap_findalldevs_ex function: %s\n", 
                 errorBuffer );
        return -1;
    }

    // if there are no adapters, print an error
    if( allAdapters == NULL )
    {
    printf( "\nNo adapters found! Make sure WinPcap is installed.\n" );
        return 0;
    }

    // print the list of adapters along with basic information about an adapter
    int crtAdapter = 0;
    for( adapter = allAdapters; adapter != NULL; adapter = adapter->next)
    {
    printf( "\n%d.%s ", ++crtAdapter, adapter->name );
    printf( "-- %s\n", adapter->description );
    }

    printf( "\n" );

    int adapterNumber;

    printf( "Enter the adapter number between 1 and %d:", crtAdapter );
    scanf_s( "%d", &adapterNumber );
    
    if( adapterNumber < 1 || adapterNumber > crtAdapter )
    {
        printf( "\nAdapter number out of range.\n" );

        // Free the adapter list
        pcap_freealldevs( allAdapters );

        return -1;
    }
    
    // parse the list until we reach the desired adapter
    adapter = allAdapters;
    for( crtAdapter = 0; crtAdapter < adapterNumber - 1; crtAdapter++ )
        adapter = adapter->next;

    // open the adapter
    adapterHandle = pcap_open( adapter->name, // name of the adapter
                               65536,         // portion of the packet to capture
                                              // 65536 guarantees that the whole 
                                              // packet will be captured
                               PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
                               1000,             // read timeout - 1 millisecond
                               NULL,          // authentication on the remote machine
                               errorBuffer    // error buffer
                              );

    if( adapterHandle == NULL )
    {
        fprintf( stderr, "\nUnable to open the adapter\n", adapter->name );

        // Free the adapter list
        pcap_freealldevs( allAdapters );

        return -1;
    }
    
    // free the adapter list
    pcap_freealldevs( allAdapters );


    // this is the most important part of the application
    // here we send the packet

    // first we create the packet

    // set mac destination address to 01 : 01 : 01 : 01 : 01 : 01
    packet[0] = 0x01;
    packet[1] = 0x01;
    packet[2] = 0x01;
    packet[3] = 0x01;
    packet[4] = 0x01;
    packet[5] = 0x01;
    
    // set mac source address to 02 : 02 : 02 : 02 : 02 : 02
    packet[6]  = 0x02;
    packet[7]  = 0x02;
    packet[8]  = 0x02;
    packet[9]  = 0x02;
    packet[10] = 0x02;
    packet[11] = 0x02;
    
    // set the rest of the packet
    for( int index = 12; index < 20; index++ )
    {
        packet[index] = 0xC4;
    }

    // send the packet
    if( pcap_sendpacket( adapterHandle, // the adapter handle
             packet, // the packet
             20 // the length of the packet
               ) != 0 )
    {
        fprintf( stderr,"\nError sending the packet: \n", pcap_geterr( adapterHandle ) );
        return -1;
    }

    system( "PAUSE" );
    return 0;
}

Conclusion

In this article, we saw what WinPcap libraries are, how they can be installed, and most importantly, some basic applications that use them. Check the documentation tutorials to explore the real power of WinPcap.

History

  • 18th October, 2008: Initial post.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)