Craft Packets with Libnet

I have written a few posts about packet crafting using the basic C functions, specifically using sendto() of a packet buffer in my article ICMP Smurf Attack as well as how to create a program for doing a TCP Syn Flood with a Raw Socket. There is however, a cleaner, more efficient way of packet crafting. It also allows you to send out specific interfaces, create a packet for special ethernet frames like VLAN, or 8023 frames – all with a simple function call. You could probably guess from the title of the article that I am referring to Libnet. Before I go any further I want to outline a few links that I found quite useful for my packet crafting endeavours:

Example: Craft and Send an IP Packet

Libnet requires you to build the packet in reverse. So for this example we will create the IP header prior to creating the Ethernet header. There are also a few options during the initialization phase, in particular stating which Injection type you would like to use:

  • LIBNET_LINK – Link layer interface. The developer needs to create packets down to the link layer.
  • LIBNET_LINK_ADV – Link layer interface in advanced mode. This allows the developer additional control over the packet being created.
  • LIBNET_RAW4 – Raw sockets interface for IPv4 (normal Internet IP). The developer needs to create packets down to the Internet layer.
  • LIBNET_RAW4_ADV – Raw sockets interface for IPv4 in advanced mode. This allows the developer additional control over the packet being created.
  • LIBNET_RAW6 – Raw sockets interface for IPv6 (next-generation IP).
  • LIBNET_RAW6_ADV – Raw sockets interface for IPv6 in advanced mode. This allows the developer additional control over the packet being created.

Depending on your needs, you may decide LIBNET_RAW4 is enough for you, thus the Ethernet layer is provided by libnet. For our example, as mentioned above, will include both IPv4 layer and Ethernet layers.

1. Initialize the Libnet Handle

In this example we assume the ether_header contains the data we require, as well as the IP header

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libnet.h>  /* Must include libnet header */
#include <syslog.h>
 
int send_packet(struct ether_header *ether, struct  iphdr *ip)
{   
        int bytesSent = 0;
	libnet_t *l;  /* Libnet Handle */
	libnet_ptag_t etherTag;  /* Return code handle for ethernet header */
	libnet_ptag_t ipTag;  /* Return code handle for IP header */
	char errbuf[LIBNET_ERRBUF_SIZE]; /* Libnet Error Buffer */
 
	if(!ether || !ip){
		fprintf(stderr, "Invalid data packet\n");
		return -1;
	}
 
	/*
	*  Libnet Handle Initialization.
	*/	
	l = libnet_init(LIBNET_LINK_ADV, "eth0", errbuf);
	if(l == NULL){
		fprintf(stderr, "ERROR: getLibnetSocket(): libnet init failed: %s \n", errbuf);
		return(-1);
	}

The second argument for the libnet_init function is the interface in which you can send your packet out. Now we build the IPv4 header.

2. Build the IPv4 Header

Since our last header (we are only going to the IP header), this must be built prior to the Ethernet Header.

ipTag = libnet_build_ipv4(
	LIBNET_IPV4_H,   /* length */
	0,               /* TOS */
	242,             /* IP ID */
	0,               /* IP Frag */
	64,              /* TTL */
	IPPROTO_UDP,     /* protocol */
	0,               /* checksum */
	ip->saddr,	 /* source IP */
	ip->daddr,	 /* destination IP */
	NULL,            /* payload */
	0,               /* payload size */
	l,               /* libnet handle */
	0); 

if (ipTag == -1) {
	fprintf(stderr, "ERROR: setup of crafted IP packet failed: \n");
	fprintf(stderr, "ERROR: on IP packet craft: %s\n", libnet_geterror(l));
	goto error;
}

Since there is no payload our payload points to NULL and the size is set to 0. The first argument is the total length of the IP packet including all subsequent data, since we don’t have a UDP or TCP header, its simply the LIBNET_IPV4_H – header length.

3. Build the Ethernet Header

The call to building the Ethernet frame. This example assumes the Ethernet header information is passed to this function:

etherTag = libnet_build_ethernet(
	ether->ether_dhost,	/* destination address */
	ether->ether_shost,	/* source address */
	ETHERTYPE_IP,		/* type of encasulated packet */
	NULL,			/* pointer to payload */
	0,			/* size of payload */
	l, 			/* libnet context */
	0); 			/* libnet protocol tag */
if (etherTag == -1) {
	fprintf(stderr, "ERROR: setup of crafted Ethernet packet failed: \n");
	fprintf(stderr, "ERROR: on Ethernet packet craft: %s\n", libnet_geterror(l));
	goto error;
}

4. Incorporate Valid IP Checksum

This is important if you want your packet to actually be sent, or received. In some cases packets with invalid checksums will not leave the wire, or the receiving entity will merely drop the packet.

libnet_toggle_checksum(l, ipTag, LIBNET_ON );

If we also had a TCP header, this function will properly set the IP and TCP checksums. Since we only have the IP header, this function will just set the IP checksum. Notice the ipTag variable passed the function. This was the return handle provided by the ipTag = libnet_build_ipv4( function.

5. Send the Packet and Close Handle

The most important piece of the puzzle. Actually send the packet!

bytesSent = libnet_write(l);
 
if (bytesSent == -1) {
	fprintf(stderr, "Error: write error for crafted packet: %s\n", libnet_geterror(l));
	goto error;
}else
	fprintf(stdout, "Packet sent: %u\n", bytesSent);
 
/*  Shut down the interface. */
libnet_destroy(l);

Conclusion

As you can see from these examples, using libnet is merely following a recipe of what you need to create. Libnet provides a large set of packet construction functions, the ability to bind to a specific interface, and even set correct checksums! All in a nice package.

There is also a thorough outline of using Libnet here: Libnet Tutorial