Saturday, October 26, 2013

Creating a simple and fast packet sniffer in C++

I have seen several articles on the web about writing packet sniffers using C and C++ which suggest using raw sockets and dealing with protocol headers and endianness yourself. This is not only very tedious but also there are libraries which already deal with that for you and make it extremely easy to work with network packets.

One of them is libtins, a library I have been actively developing for the past few years. It has support for several protocols, including Ethernet, IP, IPv6, TCP, UDP, DHCP, DNS and IEEE 802.11, and it works on GNU/Linux, Windows, OSX and FreeBSD. It even works on different architectures such as ARM and MIPS, so you could go ahead and develop some application which could be executed inside routers and other devices.

Let's see how you would sniff some TCP packets and print their source and destination port and addresses:
#include <iostream>
#include <tins/tins.h>
using namespace std;
using namespace Tins;
bool callback(const PDU &pdu) {
    const IP &ip = pdu.rfind_pdu<IP>();
    const TCP &tcp = pdu.rfind_pdu<TCP>();
    cout << ip.src_addr() << ':' << tcp.sport() << " -> " 
         << ip.dst_addr() << ':' << tcp.dport() << endl;
    return true;
}

int main() {
    // Sniff on interface eth0
    Sniffer sniffer("eth0");
    sniffer.sniff_loop(callback);
}
This is the output I get when executing it:


As you can see, it's fairly simple. Let's go through the snippet and see what it's doing:
  • The callback function is the one that libtins will call for us each time a new packet is sniffed. It returns a boolean, whch indicates whether sniffing should go on or not, and takes a parameter of type PDU, which will hold the sniffed packet. This library represents packets as a series of Protocol Data Units(PDU) stacked over each other. So in this case, every packet would contain an EthernetII, IP and TCP PDUs.
  • Inside callback's body, you can see that we're calling PDU::rfind_pdu. This is a member function template which looks for the provided PDU type inside the packet, and returns a reference to it. So in the first two lines we're retrieving the IP and TCP layers, and then we're simply printing the addresses and ports.
  • Finally, in main an object of type Sniffer is constructed. When constructing it, we indicate that we want to sniff on interface eth0. After that, Sniffer::sniff_loop is called, which will start sniffing packets and calling our callback for each of them.
Note that this example will run successfully on any of the supported operating systems(as long as you use the right interface name, of course). The endianness of each of the printed fields is handled internally by the library, so you don't even have to worry about making your code work in Big Endian architectures.

Now, you may be wondering whether using libtins will make your code significantly slower. If that is your concern, then you should not worry about it at all! This library was designed keeping efficiency in mind at all times. As a consequence it's the fastest packet sniffing and interpretation library I've tried out (note that I tried several, such as scapy, dpkt, impacket and libcrafter). Go ahead and have a look at these benchmarks to see how fast it actually works.

libtins allows you to implement fast packet sniffers in very few lines of code. It also supports additional features like reassembling and following TCP streams, decrypting WPA2 traffic (both TKIP and AES) and defragmenting IP datagrams.

If you want to learn more about libtins, please visit this tutorial, which covers everything you should know before starting to develop your network sniffing application!

9 comments:

  1. The example looks pretty cool, I was thinking what would be involved in building a simple python wrapper to the library. I am actually open to help with it, however I am not very familiar with this kind of stuff so may be underestimating the effort required.

    ReplyDelete
    Replies
    1. Thanks! Actually I've already started to develop a python wrapper using Boost.Python: http://sourceforge.net/projects/pytins/. It's already working and it works very fast! If you'd like to collaborate, just contact me.

      Delete
  2. Very interesting! I know the classic scapy from python, didn't know C++ had such a nice library too!

    ReplyDelete
  3. En argentina estamos fabricando unas zapatillas ip similares, aca les dejo el link para que las vean http://www.nysoft.com.ar/zapatilla-ip-zipa-4-bocas/

    ReplyDelete
  4. It`s interesting. Can u send me the full source code, plz ?

    ReplyDelete
  5. may i know how you include your libtins as library inside your code?

    ReplyDelete
    Replies
    1. There's information about that on the website:

      http://libtins.github.io/download/#using

      Delete
  6. does this support dropping specified packets

    ReplyDelete
  7. The output with the same code above in my pc is with IP address not in xxx.xxx.xxx.xxx format. How can I change that to xxx.xxx.xxx.xxx format?

    2953143562 : 54534 -> 824300962 : 443
    807523746 : 443 -> 2953143562 : 56176
    2953143562 : 56176 -> 807523746 : 443
    2953143562 : 54242 -> 3994605996 : 443
    3994605996 : 443 -> 2953143562 : 54242
    2953143562 : 54242 -> 3994605996 : 443
    2953143562 : 54242 -> 3994605996 : 443

    ReplyDelete