In this section we'll have a look at how the packet sending mechanism works on libtins.
PacketSender class is the responsible for sending packets
over the network. Internally, it stores raw sockets for different socket
layers(2 and 3 for example).
is serialized into a an array of bytes and sent through the appropriate
Sending network layer
PDUs, such as
IPv6 is quite intuitive:
Note that no source address was specified in the
This uses by default the address 0.0.0.0. However, when sending network
PDUs, if the source address is 0.0.0.0, the
perform a lookup on the routing table to find out which should be the
source address and automatically sets it. This is done by the network
driver already, but some transport layer protocols such as
require this address when calculating the checksum, so this must be
done by the library as well.
When sending link layer
PDUs, such as
is one more thing that should be kept in mind. In this case, the packet
must be sent through a specific network interface. You can specify this
when sending it:
That will send the packet through the eth0 interface.
It is quite common to use the same network interface to send several
PacketSender contains a default interface, in which
PDU's are sent when using the
Note that by default this interface is invalid, so you need to set it
before sending link layer
PDUs as shown above:
So far we've seen how to send packets, but what if you're expecting a response to that packet? Let's take as an example an ARP request. After it's sent, you'll most likely want to receive a response.
This could be achieved by sniffing while sending the packet, checking each sniffed packet until the response is found. However, in order to match the packet response, it would be necessary to perform several protocol dependent comparisons. In the case of an ARP response, it would be fairly straightforward. However, other protocols require checking destination and source address and ports, identifier numbers, etc.
Fornutately, a sending and receiving mechanism has already been included
in the library. This can be achieved by using
which provides two overloads:
NetworkInterface parameter serves the same purpose as in
Let's see how it could be used to perform an
ARP request and
receiving its response:
Note that inside
PacketSender::send_recv, packets read from the
socket will be matched against the sent one until a valid one is found.
Just as a side note, hardware addresses can be resolved much easily,
Going back to the sending and receiving mechanism, we could also use it to determine whether a TCP port is open:
As a last example, the following code resolves a domain name using
In the examples above, some of the protocols used, such as
TCP contain a checksum field. This checksum must be
calculated everytime the packet is sent. libtins does this
automatically: everytime a packet is serialized(this happens inside
PacketSender::send), the checksums are calculated; so there is
no need for you to worry about them.
One thing that should be noticed is that the raw socket opening
operation is not thread-safe, so in case you're having multiple
writers, you should explicitly open the required sockets yourself(this
can be done through
PacketSender::open_l3_socket). Otherwise, the sockets will be
open when needed.