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 ];
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( allAdapters == NULL )
{
printf( "\nNo adapters found! Make sure WinPcap is installed.\n" );
return 0;
}
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" );
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, 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:
#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 ];
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( allAdapters == NULL )
{
printf( "\nNo adapters found! Make sure WinPcap is installed.\n" );
return 0;
}
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" );
pcap_freealldevs( allAdapters );
return -1;
}
adapter = allAdapters;
for( crtAdapter = 0; crtAdapter < adapterNumber - 1; crtAdapter++ )
adapter = adapter->next;
adapterHandle = pcap_open( adapter->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errorBuffer );
if( adapterHandle == NULL )
{
fprintf( stderr, "\nUnable to open the adapter\n", adapter->name );
pcap_freealldevs( allAdapters );
return -1;
}
printf( "\nCapture session started on adapter %s...\n", adapter->name );
pcap_freealldevs( allAdapters );
int retValue;
while( ( retValue = pcap_next_ex( adapterHandle,
&packetHeader,
&packetData ) ) >= 0 )
{
if( retValue == 0 )
continue;
printf( "length of packet: %d\n", packetHeader->len );
}
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 ];
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( allAdapters == NULL )
{
printf( "\nNo adapters found! Make sure WinPcap is installed.\n" );
return 0;
}
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" );
pcap_freealldevs( allAdapters );
return -1;
}
adapter = allAdapters;
for( crtAdapter = 0; crtAdapter < adapterNumber - 1; crtAdapter++ )
adapter = adapter->next;
adapterHandle = pcap_open( adapter->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errorBuffer );
if( adapterHandle == NULL )
{
fprintf( stderr, "\nUnable to open the adapter\n", adapter->name );
pcap_freealldevs( allAdapters );
return -1;
}
pcap_freealldevs( allAdapters );
packet[0] = 0x01;
packet[1] = 0x01;
packet[2] = 0x01;
packet[3] = 0x01;
packet[4] = 0x01;
packet[5] = 0x01;
packet[6] = 0x02;
packet[7] = 0x02;
packet[8] = 0x02;
packet[9] = 0x02;
packet[10] = 0x02;
packet[11] = 0x02;
for( int index = 12; index < 20; index++ )
{
packet[index] = 0xC4;
}
if( pcap_sendpacket( adapterHandle, packet, 20 ) != 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.