Skip to content
November 20, 2010 / dranaxum

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;)

3 Comments

Leave a Comment
  1. Jonathan Brown / Feb 2 2012 6:36 pm

    Thank you so much for making this. I would not have been able to make this myself.

  2. suninwinter / May 2 2012 12:27 pm

    haha~ Thank you~

Trackbacks

  1. Cum sa folosesti WinPcap cu C#? | WorldIT

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: