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