Introduction to the WinPcap Networking Libraries






4.33/5 (22 votes)
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.
After downloading and running the executable file, following the instructions given by the wizard, the WinPcap components are installed on your computer.
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.
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”.
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:
Under the “Configuration Properties -> Linker -> General” tab, add the WinPcap library path (“C:\WpdPack_4_0_2\WpdPack\Lib”) to Additional Library Directories:
Under the “Configuration Properties -> Linker -> Input” tab, add the two main WinPcap libraries (wpcap.lib and Packet.lib) to Additional Dependencies:
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:
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.
#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:
- rpcap://\Device\NPF_GenericDialupAdapter -- Network adapter 'Adapter for generic dialup and VPN capture' on local host
- 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, afterto_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:
#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:
#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.