Using WinPcap in C# (Packet capture)
WinPcap is a very useful tool which can enables users to capture windows packets. On their website they offer a development pack but only for C/C++ programmers. So this is why I decided to write my own (simple) class for capturing packets in C# importing the wpcap.dll . Before showing the code, you must know that in order for your program to run as it should in Windows Vista/7 you must run it as administrator, otherwise it won’t even find the (network) devices.
In order to import the functions we must first define some structures:
[StructLayout(LayoutKind.Sequential)]
struct pcap_if
{
public IntPtr next;
public string name; //name of device
public string description; //description of device
public pcap_addr addresses;
public int flags;
}
[StructLayout(LayoutKind.Sequential)]
struct pcap_addr
{
public IntPtr next;
public IntPtr addr;
public IntPtr netmask;
public IntPtr broadaddr;
public IntPtr dstaddr;
}
[StructLayout(LayoutKind.Sequential)]
struct sockaddr
{
public Int16 sa_family;
public string sa_data;
}
[StructLayout(LayoutKind.Sequential)]
struct pcap_pkthdr
{
public timeval ts;
public int caplen; //captured length
public int len; //packet length
}
[StructLayout(LayoutKind.Sequential)]
struct timeval
{
public int tv_sec;
public int tv_usec;
}
//some credentials if we want to capture packets remotely
//CAN BE VERY USEFUL!!
[StructLayout(LayoutKind.Sequential)]
struct pcap_rmtauth
{
public int type;
public string username;
public string password;
};
The following step we must do is defining three constants (there are more which are supported, but we don’t need them for this program):
const int PCAP_ERRBUF_SIZE = 256;
const int PCAP_OPENFLAG_PROMISCUOUS = 1;
const string PCAP_SRC_IF_STRING = "rpcap://";
Now we must also define the functions we will use from wpcap.dll :
[DllImport("wpcap.dll")]
static extern IntPtr pcap_open(string source, int snaplen, int flags, int read_timeout, IntPtr auth, ref IntPtr errbuff);
[DllImport("wpcap.dll")]
static extern void pcap_freealldevs(IntPtr alldevs);
//auth is a managed pointer to a structure of type pcap_rmtauth
[DllImport("wpcap.dll")]
static extern int pcap_findalldevs_ex(string source, IntPtr auth, ref IntPtr alldevs, ref IntPtr errbuff);
[DllImport("wpcap.dll")]
static extern int pcap_next_ex(IntPtr conn, ref IntPtr header, ref IntPtr packetdata);
[DllImport("wpcap.dll")]
static extern void pcap_close(IntPtr conn);
In order to get all the devices you can use this function I created:
public List<deviceDetails> getDeviceList()
{
try
{
List ret = new List();
IntPtr ip = allDevices;
while (ip != IntPtr.Zero)
{
pcap_if dev = (pcap_if)Marshal.PtrToStructure(ip, typeof(pcap_if));
deviceDetails dd = new deviceDetails();
dd.name = dev.name;
dd.description = dev.description;
ret.Add(dd);
ip = dev.next;
}
if (ret.Count == 0)
OnErrorEvent("No devices found!");
return ret;
}
catch (Exception ex)
{
OnErrorEvent(ex.Message);
return null;
}
}
where deviceDetails is a structure with two fields (name and description).
You can also used the class Tuple which is available in C# 4.0 like this:
public List<Tuple<string,string>> getDeviceList()
{
try
{
List ret = new List();
IntPtr ip = allDevices;
while (ip != IntPtr.Zero)
{
pcap_if dev = (pcap_if)Marshal.PtrToStructure(ip, typeof(pcap_if));
Tuple<string,string> dd = new Tuple<string,string>(dev.name,dev.description);
ret.Add(dd);
ip = dev.next;
}
if (ret.Count == 0)
OnErrorEvent("No devices found!");
return ret;
}
catch (Exception ex)
{
OnErrorEvent(ex.Message);
return null;
}
}
To open and capture packets from devices the next two functions could be used:
public IntPtr openDevice(deviceDetails dev)
{
IntPtr fp = IntPtr.Zero;
IntPtr referrbuff = IntPtr.Zero;
fp = pcap_open(dev.name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, IntPtr.Zero, ref referrbuff);
if (fp == IntPtr.Zero)
{
OnErrorEvent(PtrToString(referrbuff, PCAP_ERRBUF_SIZE));
return IntPtr.Zero;
}
return fp;
}
//fp refers to the returned pointer of the previous function.
private void startCapture(IntPtr fp,AsyncOperation async)
{
try
{
IntPtr hdr = IntPtr.Zero;
IntPtr data = IntPtr.Zero;
int res;
pcap_pkthdr header = new pcap_pkthdr();
while ((res = pcap_next_ex(fp, ref hdr, ref data)) >= 0)
{
if (res == 0)
continue;
header = (pcap_pkthdr)Marshal.PtrToStructure(hdr, typeof(pcap_pkthdr));
//asynchronously calls the function OnPacketCaptured with the arguments: data (the captured data) and header.caplen (the length of the data).
async.Post (
delegate (object e) {
object[] inputdata = (object[])e;
OnPacketCapturedEvent((int)inputdata[0], PtrToString((IntPtr)inputdata[1], (int)inputdata[0]));
},
(object)(new object[] {header.caplen,data}
));
hdr = IntPtr.Zero;
data = IntPtr.Zero;
}
}
catch (Exception ex)
{
OnErrorEvent(ex.Message);
stopCapture(fp);
}
}
I think the code is straight forward so as you to understand how to use winpcap in C#. HOWEVER, NOTICE that I didn’t define some functions in this post (e.g. : OnErrorEvent, PtrToString, stopCapture, etc.) as well as I didn’t tell you how to call startCapture as you need an AsyncOperation parameter.
This should be for you to exercise!!
If you still struggle to understand some of the functions/parameters in winpcap I recommend you download the developer pack and look through the C/C++ source codes as they are fully documented using comments.
PS: In order to use DllImport, the Marshal class etc. you should import System.Runtime.InteropServices in your code. (using System.Runtime.InteropServices;)

One Comment
Leave a CommentTrackbacks