In this section we'll have a look at how libtins works, and how to perform packet crafting, sending and sniffing.
This section assumes you already know how to compile applications and link them with libtins.
So how does libtins work? libtins is conformed by
sender and sniffer classes, classes that represent addresses, and some
helper functions which make your life easier.
We'll first have a look at what a
PDU object is. Every
PDU implemented in the library(say
UDP, etc) is a class that inherits an
abstract class named
This class contains methods which can retrieve the actual protocol data unit size and its type, among other things. It also contains a method called send which allows you to effectively send that packet through the network.
PDU objects also support stacking. That means one
PDU object(disregarding its actual type), can have 0 or 1
PDU. This is a very logical way of imagining a
network packet. Suppose you create an
Ethernet II frame,
and then add an
IP datagram on top of it, followed by a
TCP frame. That structure would look like this inside
As you may imagine, a
PDU's inner pdu can be retrieved using
PDU::inner_pdu(). Let's see an code example of
how this situation could be reproduced:
So what have we done here? The method
sets the given parameter, as the callee's inner
object passed as an argument must have been allocated using
and from that point on, that
PDU is now owned by its parent,
meaning that the destruction of that object will be handled by it. So
in the above example there is no actual memory leak. On eth's
destructor, both the allocated
objects will be destroyed and their memory released.
Note that if you want to store a copy and not the actual pointer, you
can use the
PDU::clone function, which returns a copy of
PDU's concrete type, including all of its stacked
There is a simpler way to nest
PDUs. For those who have used
you may be used to creating a
PDU stack using the division
operator. libtins supports this as well!
The code above can be rewritten as the following:
Note that the
TCP temporary objects created in
the example above, are cloned using the
Both IP and hardware addresses are handled using the
HWAddress<> classes. All of
these classes can be constructed from an
c-string containing an appropriate representation(dotted-notation
IPv4Address, semicolon notation for
This addresses can be implicitly converted to an integral value, but
this is used inside the library, so you don't have to worry about it.
As you can notice from above, a default constructed
corresponds to the dotted-notation address
These classes also provide a constructor that takes an
which is extremely useful when using default values for certain parameters
to functions/constructors. In the above example's last couple of lines,
both an IPv4 and an IPv6 addresses are written to stdout. This classes
define the output operator(
operator<<), so it's easier
to serialize them.
HWAddress<> class template is defined as follows:
Where the n non-type template parameter indicates the length of
the address(tipically 6 for network interfaces), and the
template parameter indicates the type of each of those n elements
(this shouldn't normally be changed,
uint8_t should do).
HWAddress objects can be constructed from both
const Storage* and HWAddress of any length. They
can also be compared for equality, and provide some helper functions to
allow iteration over the address:
libtins also supports address ranges. This is very useful for several purposes, such as classifying traffic into different subnetworks.
Creating address ranges is very intuitive, using either a slash-dotation, or a netmask:
Now, what can you do with an address range? You can either iterate it, or ask it if a specific address is inside that network:
But wait, there's more. You can also create ranges of hardware addresses. Why is this useful? Using this, you can use the OUI specifiers to determine which is the vendor of a specific network device:
The last helper class reviewed here is
class represents the abstraction of a network interface. It can be
constructed from the interface's name(as string), and from an
IPv4Address. This last constructor creates the interface that would be
the gateway if some packet were to be sent to the given ip address:
You can also retrieve an interface's name using
Note that this function searches through the system's interfaces and
retrieves the name every time it is called, so you might want to call it
once and store the return value.
Writing packets to a pcap file is very simple as well. The
PacketWriter class takes the name of the file in which you want
to store packets as its argument, and a flag indicating which will be
the lowest layer written to the file. That means, if you're writing
EthernetII PDUs, you should use the
flag, while on wireless interfaces you should use
PacketWriter::DOT11, depending on the encapsulation used in
As of version 3.2 , there's a simpler way to indicate the link layer
protocol to be used on the packets written by a
This can be done by instantiating the template class
with a link layer protocol
PDU as its template argument.
This makes it easier to use this class, since you won't have to
remember which is the identifier name for some link layer protocol.
The following example illustrates this usage:
PacketWriter is created, you can write
PDUs to it
PacketWriter::write method. This method contains 2
overloads: one takes a
PDU&, the other one takes two template
end. The latter will iterate
through the range [start, end) and write the
in each position of the range. This will work both if
PDU&, or if dereferecing it several times leads to
PDU&. This means a
work as well.
This example creates a
std::vector containing one
EthernetII PDU, and writes it to a pcap file using both
Now we're going to use most of the classes listed above to create a packet and send it:
Note that the creation of that packet can be done in one line, using
operator/ rather than
The packet sending mechanism is addressed in the third section of this tutorial.