Thursday, April 24, 2014

libnet library part 2: Injecting TCP and UDP packets


In the libnet library part 1 (http://network-development.blogspot.com/2014/02/libnet-library-part-1-introduction-and.html) post we learned how to send an echo ICMP packet and also created the build_ipv4() and write_packet() helper functions. In this post we will add the sendTCP() and sendUDP() functions to our libnet library. If you have not read part 1, I would recommend you read that post prior to reading this one.

libnet_lib header file:
Add the following lines to the libnet_lib header file to define the sendTCP() and sendUDP() functions.

bool sendUDP(char* addr, int port, char *payload, char *interface);
bool sendTCP(char *addr, int port, u_int8_t flags, char *payload, char *interface);

The sendUDP() functions accepts the following four arguments:

char *addr: This is the address to send the packet too.
int port: This is the port to send the packet too.
char *payload: This is any payload that you wish to send in the TCP packet
char *interface: The interface to send the packet though. By setting this to NULL libnet will pick the most appropriate interface to send the packet. Unfortunately on some systems (like my Ubuntu laptop) this automatically defaults to eth0 even if it is not connected to anything.

The sendTCP() function accepts the following five arguments:

char *addr: This is the address to send the packet too.
int port: This is the port to send the packet too.
u_int8_t flags: This is the TCP flags to set in the packet header. The options are:
TH_ACK
TH_FIN
TH_PUSH
TH_RST
TH_SYN
TH_URG
To set multiple flags you would OR them like this: TH_ACK|TH_SYN.
char *payload: This is any payload that you wish to send in the TCP packet
char *interface: The interface to send the packet though. By setting this to NULL libnet will pick the most appropriate interface to send the packet. Unfortunately on some systems (like my Ubuntu laptop) this automatically defaults to eth0 even if it is not connected to anything.


sendUDP():
The sendUDP() function will build and inject a UDP packet into the network. Lets take a look at the code and then we will examine it:

bool sendUDP(char* addr, int port, char *payload, char *interface) {
libnet_t *lnet;

u_int16_t id,seq;
char errbuf[LIBNET_ERRBUF_SIZE];

lnet = libnet_init(LIBNET_RAW4, interface, errbuf);
if ( lnet == NULL ) {
printf("Error with libnet_init(): %s", errbuf);
return false;
}

/* Generating a random id */
libnet_seed_prand (lnet);
id = (u_int16_t)libnet_get_prand(LIBNET_PR16);

/* Building UDP header */
seq = 1;

if (libnet_build_udp(
libnet_get_prand (LIBNET_PRu16),
port,
LIBNET_UDP_H+ sizeof(payload),
0,
(u_int8_t*)payload,
sizeof(payload),
lnet,
0) == -1)
{
printf("Error building UDP header: %s\n",libnet_geterror(lnet));
libnet_destroy(lnet);
return false;
}


build_ipv4 (addr, IPPROTO_UDP, sizeof(payload) + LIBNET_UDP_H, lnet);

bool success = write_packet (lnet);
libnet_destroy(lnet);
return success;
}

The sendUDP() function begins by calling the libnet_init() function to initiate the libnet context. The libnet context needs to be initialized prior to calling any other libnet function. The prototype for the libnet_init function is: libnet_init(int injection_type, const char *device, char *err_buf); As you can see, this function takes three arguments which are:

int injection_type: This is the libnet injection type. I almost exclusively use LIBNET_RAW4 which tells libnet to automatically create the link layer headers for me. Some of the other possible values are: LIBNET_LINK , LIBNET_LINK_ADV , LIBNET_RAW4 , LIBNET_
RAW4_ADV , LIBNET_RAW6 , and LIBNET_RAW6_ADV.
const char *device: This is the name of the interface to use. This can be set to NULL to let libnet choose the interface.
char *err_buf: This buffer will contain any errors that occur if something goes wrong with the request.

After we initiate the libnet context we then verify that it was properly initiated. If it was not properly initiated we return false to let the calling function know that the packet was not sent out.

Next we need to create a random number to be used as the identifier. We use the libnet_seed_prand() function to seed the pseudo-random number generator and then the libnet_get_prand() function to retrieve a random number. The LIBNET_PR16 constant specifies a number between 0 and 32767.

Now we will build the UDP header. We use the libnet_build_udp() function to create the UDP header. This function has a prototype of: libnet_build_udp(uint16_t sp, uint16_t dp, uint16_t len, uint16_t sum, const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag). The eight arguments for this function are:

uint16_t sp: This is the source port that the packet is sent from on the local device. We use the libnet_get_prand() function to generate a random port.
uint16_t dp: This is the destination port that the packet is sent to on the destination device.
uint16_t len: This is the size of the UDP header and the payload.
uint16_t sum: We set this to 0 so libnet will autogenerate a checksum for us.
const uint8_t* payload: This is any payload that we want to send.
uint32_t payload_s: The size of the payload.
libnet_t *l: This is the libnet context to be used with this header.
libnet_ptag_t ptag: This is set to 0 for generating a new header.

If the libnet_build_udp() function returns -1, there was a problem generating the header. If this happens we return false to the calling function to let it know that the packer was not sent. If the libnet_build_udp() function was successful, we generate the ICMPv4 header by calling the build_ipv4() function that we created in part 1 of this tutorial. The write_packet() function then injects our packet into the network. Finally we call the libnet_destory() function to release the memory used by the libnet context.

sendTCP():
The sendTCP() function will build and inject a TCP packet into the network. We will take a look at the code and then examine it:

bool sendTCP(char *addr, int port, u_int8_t flags, char* payload, char *interface)
{

libnet_t *lnet;
u_int16_t id,seq;
char errbuf[LIBNET_ERRBUF_SIZE];

lnet = libnet_init(LIBNET_RAW4, interface, errbuf);
if ( lnet == NULL ) {
printf("Error with libnet_init(): %s", errbuf);
return false;
}

/* Generating a random id */
libnet_seed_prand (lnet);
id = (u_int16_t)libnet_get_prand(LIBNET_PR16);

/* Building TCP header */
seq = 1;

if (libnet_build_tcp (libnet_get_prand (LIBNET_PRu16),
port,
0,
0,
flags,
1024,
0,
0,
LIBNET_TCP_H,
(u_int8_t*)payload,
sizeof(payload),
lnet,
0) == -1)
{
printf("Error building TCP header: %s\n",libnet_geterror(lnet));
libnet_destroy(lnet);
return false;
}

build_ipv4 (addr, IPPROTO_TCP, sizeof(payload) + LIBNET_TCP_H, lnet);

bool success = write_packet (lnet);
libnet_destroy(lnet);
return success;

}

The sendTCP() function is very similar to the sendUDP() function except we use the libnet_build_tcp() function to create the TCP packet. The prototype for the libnet_build_tcp() function is: libnet_build_tcp(uint16_t sp, uint16_t dp, uint32_t seq, uint32_t ack, uint8_t control, uint16_t win, uint16_t sum, uint16_t urg, uint16_t len, const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag). The arguments for the libnet_build_tcp() function is:

uint16_t sp: This is the source port that the packet is sent from on the local device. We use the libnet_get_prand() function to generate a random port.
uint16_t dp: This is the destination port that the packet is sent to on the destination device.
uint32_t seq: This is the sequence number of the packet.
uint32_t ack: This is the acknowledgement number.
uint8_t control: This is where the TCP flags are set. The flags are passed into the sendTCP() function.
uint16_t win: This is the maximum window size.
uint16_t sum: We set this to 0 so libnet will autogenerate a checksum for us.
uint16_t urg: This sets the urgent flag.
uint16_t len: This is the size of the UDP header and the payload.
const uint8_t* payload: This is any payload that we want to send.
uint32_t payload_s: The size of the payload.
libnet_t *l: This is the libnet context to be used with this header.
libnet_ptag_t ptag: This is set to 0 for generating a new header.

Below is the full code for the libnet_lib.c library.


#include "libnet_lib.h"
#include <libnet.h>

bool build_ipv4(char *addr, u_int8_t proto, u_int32_t psize, libnet_t *lnet) {
u_int32_t target, source;
u_int16_t id;

target = libnet_name2addr4(lnet, addr, LIBNET_DONT_RESOLVE);

source = libnet_get_ipaddr4(lnet);
if ( source == -1 ) {
printf("Error retrieving IP address: %s\n",libnet_geterror(lnet));
libnet_destroy(lnet);
return false;
}

libnet_seed_prand (lnet);
id = (u_int16_t)libnet_get_prand(LIBNET_PR16);

if( libnet_build_ipv4(LIBNET_IPV4_H + psize,
0,
id,
0,
64,
proto,
0,
source,
target,
NULL,
0,
lnet,
0) == -1)
{
printf("Error building IP header: %s\n",libnet_geterror(lnet));
libnet_destroy(lnet);
return false;
}
return true;
}

bool write_packet(libnet_t *lnet) {
int bytes_written = libnet_write(lnet);
if ( bytes_written != -1 ) {
printf("%d bytes written to device %s.\n", bytes_written, libnet_getdevice(lnet));
return true;
} else {
printf("Error writing packet: %s\n",libnet_geterror(lnet));
return false;
}
}

bool sendICMPEcho(char *addr, char *payload, int type, char *interface)
{
libnet_t *lnet;

u_int16_t id,seq;
char errbuf[LIBNET_ERRBUF_SIZE];

lnet = libnet_init(LIBNET_RAW4, interface, errbuf);
if ( lnet == NULL ) {
printf("Error with libnet_init(): %s\n", errbuf);
return false;
}

/* Generating a random id */
libnet_seed_prand (lnet);
id = (u_int16_t)libnet_get_prand(LIBNET_PR16);

/* Building ICMP header */
seq = 1;

if (libnet_build_icmpv4_echo(type,
0,
0,
id,
seq,
(u_int8_t*)payload,
sizeof(payload),
lnet,
0) == -1)
{
printf("Error building UDP header: %s\n",libnet_geterror(lnet));
libnet_destroy(lnet);
return false;
}

if (!build_ipv4 (addr, IPPROTO_ICMP, sizeof(payload) + LIBNET_ICMPV4_ECHO_H, lnet))
return false;

bool success = write_packet (lnet);

libnet_destroy(lnet);
return success;
}

bool sendTCP(char *addr, int port, u_int8_t flags, char* payload, char *interface)
{

libnet_t *lnet;
u_int16_t id,seq;
char errbuf[LIBNET_ERRBUF_SIZE];

lnet = libnet_init(LIBNET_RAW4, interface, errbuf);
if ( lnet == NULL ) {
printf("Error with libnet_init(): %s", errbuf);
return false;
}

/* Generating a random id */
libnet_seed_prand (lnet);
id = (u_int16_t)libnet_get_prand(LIBNET_PR16);

/* Building TCP header */
seq = 1;

if (libnet_build_tcp (libnet_get_prand (LIBNET_PRu16),
port,
0,
0,
flags,
1024,
0,
0,
LIBNET_TCP_H,
(u_int8_t*)payload,
sizeof(payload),
lnet,
0) == -1)
{
printf("Error building TCP header: %s\n",libnet_geterror(lnet));
libnet_destroy(lnet);
return false;
}

build_ipv4 (addr, IPPROTO_TCP, sizeof(payload) + LIBNET_TCP_H, lnet);

bool success = write_packet (lnet);
libnet_destroy(lnet);
return success;

}

bool sendUDP(char* addr, int port, char *payload, char *interface) {
libnet_t *lnet;

u_int16_t id,seq;
char errbuf[LIBNET_ERRBUF_SIZE];

lnet = libnet_init(LIBNET_RAW4, interface, errbuf);
if ( lnet == NULL ) {
printf("Error with libnet_init(): %s", errbuf);
return false;
}

/* Generating a random id */
libnet_seed_prand (lnet);
id = (u_int16_t)libnet_get_prand(LIBNET_PR16);

/* Building UDP header */
seq = 1;

if (libnet_build_udp(
libnet_get_prand (LIBNET_PRu16),
port,
LIBNET_UDP_H+ sizeof(payload),
0,
(u_int8_t*)payload,
sizeof(payload),
lnet,
0) == -1)
{
printf("Error building UDP header: %s\n",libnet_geterror(lnet));
libnet_destroy(lnet);
return false;
}


build_ipv4 (addr, IPPROTO_UDP, sizeof(payload) + LIBNET_UDP_H, lnet);

bool success = write_packet (lnet);
libnet_destroy(lnet);
return success;
}

No comments:

Post a Comment