To compile any of these examples (you can download the C files from the corresponding links) simply:
shattered:~> gcc -Wall `libnet-config --defines` libnet-example-x.c -o libnet-example-x `libnet-config --libs`
#include <libnet.h>
void usage(char *);
int
main(int argc, char **argv)
{
int network,
/* our network interface */
packet_size,
/* packet size */
c;
/* misc */
u_long src_ip, dst_ip;
/* ip addresses */
u_short src_prt, dst_prt;
/* ports */
u_char *cp, *packet;
/* misc / packet */
printf("libnet example code:\tmodule
1\n\n");
printf("packet injection interface:\traw
socket\n");
printf("packet type:\t\t\tTCP
[no payload]\n");
src_ip = 0;
dst_ip = 0;
src_prt = 0;
dst_prt = 0;
Standard command line argument parsing. We require a source IP and a destination IP, both in the form "ip.ip.ip.ip.port".
while((c = getopt(argc, argv, "d:s:"))
!= EOF)
{
switch
(c)
{
/*
* We expect the input to be of the form `ip.ip.ip.ip.port`.
We
* point cp to the last dot of the IP address/port string and
* then seperate them with a NULL byte. The optarg now points
to
* just the IP address, and cp points to the port.
*/
case 'd':
if (!(cp = strrchr(optarg, '.')))
{
usage(argv[0]);
}
*cp++ = 0;
dst_prt = (u_short)atoi(cp);
if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
{
libnet_error(LIBNET_ERR_FATAL, "Bad destination IP address: %s\n", optarg);
}
break;
case 's':
if (!(cp = strrchr(optarg, '.')))
{
usage(argv[0]);
}
*cp++ = 0;
src_prt = (u_short)atoi(cp);
if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
{
libnet_error(LIBNET_ERR_FATAL, "Bad source IP address: %s\n", optarg);
}
break;
}
}
if (!src_ip || !src_prt || !dst_ip
|| !dst_prt)
{
usage(argv[0]);
exit(EXIT_FAILURE);
}
Our packet is a TCP/IP packet with no payload, so we only need LIBNET_IP_H + LIBNET_TCP_H (40 bytes) of memory.
/*
* We're just going
to build a TCP packet with no payload using the
* raw sockets API,
so we only need memory for a TCP header and an IP
* header.
*/
packet_size = LIBNET_IP_H + LIBNET_TCP_H;
We allocate the heap memory for our packet. If it failed, this would be a fatal error that we couldn't recover from so we would be done. When libnet_error is called with the LIBNET_ERR_FATAL severity, the program exits. This is only defined exit point inside of libnet.
/*
* Step 1: Memory initialization
(interchangable with step 2).
*/
libnet_init_packet(packet_size,
&packet);
if (packet == NULL)
{
libnet_error(LIBNET_ERR_FATAL,
"libnet_init_packet failed\n");
}
Next we open up our network interface. Again failure is fatal.
/*
* Step 2: Network
initialization (interchangable with step 1).
*/
network = libnet_open_raw_sock(IPPROTO_RAW);
if (network == -1)
{
libnet_error(LIBNET_ERR_FATAL,
"Can't open network.\n");
}
Now the fun begins. Like so many tinker toys, or so much capsula, we build our packets. Note that no consideration is given to data-types or byte-ordering (well almost no consideration for data-types). This is all taken care of inside of libnet. All you have to worry about is what values to stuff in there. Notice that the order we call the modular packet constructors is unimportant. The major thing to note is that we pass in the packet at the correct memory location.
/*
* Step 3: Packet construction
(IP header).
*/
libnet_build_ip(LIBNET_TCP_H,
/* size of the packet sans IP header */
IPTOS_LOWDELAY, /* IP tos
*/
242,
/* IP ID */
0,
/* frag stuff */
48,
/* TTL */
IPPROTO_TCP,
/* transport protocol */
src_ip,
/* source IP */
dst_ip,
/* destination IP */
NULL,
/* payload (none) */
0,
/* payload length */
packet);
/* packet header memory */
Notice the TCP builder gets the packet memory buffer at LIBNET_IP_H (20) bytes.
/*
* Step 3: Packet construction
(TCP header).
*/
libnet_build_tcp(src_prt,
/* source TCP port */
dst_prt,
/* destination TCP port */
0xa1d95,
/* sequence number */
0x53,
/* acknowledgement number */
TH_SYN,
/* control flags */
1024,
/* window size */
0,
/* urgent pointer */
NULL,
/* payload (none) */
0,
/* payload length */
packet + LIBNET_IP_H); /* packet header memory */
Perform our checksum on the TCP header only. Since we are using the raw sockets api, the kernel will handle our IP header checksum for us. How thoughtful!
/*
* Step 4: Packet checksums
(TCP header only).
*/
if (libnet_do_checksum(packet,
IPPROTO_TCP, LIBNET_TCP_H) == -1)
{
libnet_error(LIBNET_ERR_FATAL,
"libnet_do_checksum failed\n");
}
In you go! The packet is sent on it's merry little way!
/*
* Step 5: Packet injection.
*/
c = libnet_write_ip(network, packet,
packet_size);
if (c < packet_size)
{
libnet_error(LN_ERR_WARNING,
"libnet_write_ip only wrote %d bytes\n", c);
}
else
{
printf("construction
and injection completed, wrote all %d bytes\n", c);
}
Since we're good programmers, we always shut things down when we are done.
/*
* Shut down the interface.
*/
if (libnet_close_raw_sock(network)
== -1)
{
libnet_error(LN_ERR_WARNING,
"libnet_close_raw_sock couldn't close the interface");
}
/*
* Free packet memory.
*/
libnet_destroy_packet(&packet);
return (c == -1 ? EXIT_FAILURE
: EXIT_SUCCESS);
}
void
usage(char *name)
{
fprintf(stderr, "usage: %s -s
s_ip.s_port -d d_ip.d_port\n", name);
}
/* EOF */
#include <libnet.h>
void usage(char *);
u_char enet_src[6] = {0x0d, 0x0e, 0x0a, 0x0d, 0x00,
0x00};
u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff,
0xff};
int
main(int argc, char *argv[])
{
int packet_size,
/* size of our packet */
c;
/* misc */
u_long src_ip, dst_ip;
/* source ip, dest ip */
u_char *packet;
/* pointer to our packet buffer */
char err_buf[LIBNET_ERRBUF_SIZE];
/* error buffer */
u_char *device;
/* pointer to the device to use */
struct libnet_link_int *network;
/* pointer to link interface struct */
printf("libnet example code:\tmodule
2\n\n");
printf("packet injection interface:\tlink
layer\n");
printf("packet type:\t\t\tICMP
net mask [no payload]\n");
device = NULL;
src_ip = 0;
dst_ip = 0;
This time, we have an additional `device` to specify the link layer device to use.
while ((c = getopt(argc, argv,
"i:d:s:")) != EOF)
{
switch
(c)
{
case 'd':
if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
{
libnet_error(LIBNET_ERR_FATAL, "Bad destination IP address: %s\n", optarg);
}
break;
case 'i':
device = optarg;
break;
case 's':
if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
{
libnet_error(LIBNET_ERR_FATAL, "Bad source IP address: %s\n", optarg);
}
break;
default:
exit(EXIT_FAILURE);
}
}
if (!src_ip || !dst_ip)
{
usage(argv[0]);
exit(EXIT_FAILURE);
}
If a device isn't specified, libnet will attempt to choose one for you. libnet_select_device will return the first `up` non-loopback device it finds.
/*
* Step 1: Network
Initialization (interchangable with step 2).
*/
if (device == NULL)
{
struct
sockaddr_in sin;
/*
* Try to locate a device.
*/
if (libnet_select_device(&sin,
&device, err_buf) == -1)
{
libnet_error(LIBNET_ERR_FATAL, "libnet_select_device failed: %s\n", err_buf);
}
printf("device:\t\t\t\t%s\n",
device);
}
Instead of opening a raw socket, we're opening up a link layer interface.
if ((network = libnet_open_link_interface(device,
err_buf)) == NULL)
{
libnet_error(LIBNET_ERR_FATAL,
"libnet_open_link_interface: %s\n", err_buf);
}
The ethernet header needs to be specified explicitly in the packet size.
/*
* We're going to build
an ICMP packet with no payload using the
* link-layer API,
so this time we need memory for a ethernet header
* as well as memory
for the ICMP and IP headers.
*/
packet_size = LIBNET_IP_H + LIBNET_ETH_H
+ LIBNET_ICMP_MASK_H;
/*
* Step 2: Memory Initialization
(interchangable with step 1).
*/
if (libnet_init_packet(packet_size,
&packet) == -1)
{
libnet_error(LIBNET_ERR_FATAL,
"libnet_init_packet failed\n");
}
/*
* Step 3: Packet construction
(ethernet header).
*/
libnet_build_ethernet(enet_dst,
enet_src,
ETHERTYPE_IP,
NULL,
0,
packet);
/*
* Step 3: Packet construction
(ICMP header).
*/
libnet_build_icmp_mask(ICMP_MASKREPLY,
/* type */
0,
/* code */
242,
/* id */
0,
/* seq */
0xffffffff,
/* mask */
NULL,
/* payload */
0,
/* payload_s */
packet + LIBNET_ETH_H + LIBNET_IP_H);
/*
* Step 3: Packet construction
(IP header).
*/
libnet_build_ip(ICMP_MASK_H,
0,
/* IP tos */
242,
/* IP ID */
0,
/* Frag */
64,
/* TTL */
IPPROTO_ICMP,
/* Transport protocol */
src_ip,
/* Source IP */
dst_ip,
/* Destination IP */
NULL,
/* Pointer to payload (none) */
0,
packet + LIBNET_ETH_H); /* Packet header memory */
The IP header checksum must be explicitly computed for the link layer interface.
/*
* Step 4: Packet checksums
(ICMP header *AND* IP header).
*/
if (libnet_do_checksum(packet
+ ETH_H, IPPROTO_ICMP, LIBNET_ICMP_MASK_H) == -1)
{
libnet_error(LIBNET_ERR_FATAL,
"libnet_do_checksum failed\n");
}
if (libnet_do_checksum(packet
+ ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1)
{
libnet_error(LIBNET_ERR_FATAL,
"libnet_do_checksum failed\n");
}
/*
* Step 5: Packet injection.
*/
c = libnet_write_link_layer(network,
device, packet, packet_size);
if (c < packet_size)
{
libnet_error(LN_ERR_WARNING,
"libnet_write_link_layer only wrote %d bytes\n", c);
}
else
{
printf("construction
and injection completed, wrote all %d bytes\n", c);
}
/*
* Shut down the interface.
*/
if (libnet_close_link_interface(network)
== -1)
{
libnet_error(LN_ERR_WARNING,
"libnet_close_link_interface couldn't close the interface");
}
/*
* Free packet memory.
*/
libnet_destroy_packet(&packet);
return (c == -1 ? EXIT_FAILURE
: EXIT_SUCCESS);
}
void
usage(char *name)
{
fprintf(stderr, "usage: %s [-i
interface] -s s_ip -d d_ip\n", name);
}
/* EOF */
#include <libnet.h>
void usage(char *);
int
main(int argc, char **argv)
{
int network, n, c, number_of_packets,
packet_size;
struct libnet_arena arena, *arena_p;
u_char *packets[10];
u_long src_ip, dst_ip;
printf("libnet example code:\tmodule
3\n\n");
printf("packet injection interface:\tlink
layer\n");
printf("packet type:\t\t\tICMP_ECHO
[no payload] using an arena\n");
src_ip = 0;
dst_ip = 0;
while((c = getopt(argc, argv,
"d:s:")) != EOF)
{
switch
(c)
{
case 'd':
if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
{
libnet_error(LIBNET_ERR_FATAL, "Bad destination IP address: %s\n", optarg);
}
break;
case 's':
if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
{
libnet_error(LIBNET_ERR_FATAL, "Bad source IP address: %s\n", optarg);
}
break;
}
}
if (!src_ip || !dst_ip)
{
usage(argv[0]);
exit(EXIT_FAILURE);
}
/*
* We're just going
to build an ICMP packet with no payload using the
* raw sockets API,
so we only need memory for a ICMP header and an IP
* header.
*/
packet_size = LIBNET_IP_H + LIBNET_ICMP_ECHO_H;
/*
* Let's just build
say, 10 packets.
*/
number_of_packets = 10;
The arena can be thought of as a pool of memory that can be called upon to yield usable memory until it dries up. In this case, we'll have enough memory for 10 packets of the above packet size.
arena_p = &arena;
if (libnet_init_packet_arena(&arena_p,
number_of_packets, packet_size) == -1)
{
libnet_error(LIBNET_ERR_FATAL,
"libnet_init_packet_arena failed\n");
}
else
{
printf("Allocated
an arena of %ld bytes..\n", LIBNET_GET_ARENA_SIZE(arena));
}
network = libnet_open_raw_sock(IPPROTO_RAW);
if (network == -1)
{
libnet_error(LIBNET_ERR_FATAL,
"Can't open the network.\n");
}
We'll keep grabbing chunks of memory from the arena to build packets until it runs dry. This isn't the most useful implementation of an arena as all of the packets are the same (a for loop around in the injection call would accomplish the same thing without an arena). Arenas really become useful when you're injecting packets of different types (the arena is used to preload packets).
for (n = 0; n < number_of_packets;
n++)
{
printf("%ld
bytes remaining in arena\n", LIBNET_GET_ARENA_REMAINING_BYTES(arena));
packets[n]
= libnet_next_packet_from_arena(&arena_p, packet_size);
if (!packets[n])
{
libnet_error(LIBNET_ERR_WARNING, "Arena is empty\n");
continue;
}
libnet_build_ip(ICMP_ECHO_H,
/* Size of the payload */
IPTOS_LOWDELAY | IPTOS_THROUGHPUT, /* IP tos */
242,
/* IP ID */
0,
/* frag stuff */
48,
/* TTL */
IPPROTO_ICMP,
/* transport protocol */
src_ip,
/* source IP */
dst_ip,
/* destination IP */
NULL,
/* pointer to payload */
0,
/* payload length */
packets[n]);
/* packet header memory */
libnet_build_icmp_echo(ICMP_ECHO,
/* type */
0,
/* code */
242,
/* id */
5,
/* seq */
NULL,
/* pointer to payload */
0,
/* payload length */
packets[n] + LIBNET_IP_H);
/* packet header memory */
if (libnet_do_checksum(packets[n],
IPPROTO_ICMP, LIBNET_ICMP_ECHO_H) == -1)
{
libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
}
c = libnet_write_ip(network,
packets[n], packet_size);
if (c
< packet_size)
{
libnet_error(LN_ERR_WARNING, "libnet_write_ip only wrote %d bytes\n", c);
}
else
{
printf("construction and injection of packet %d of %d completed, wrote
all %d bytes\n", n + 1, number_of_packets, c);
}
}
libnet_destroy_packet_arena(&arena_p);
return (c == -1 ? EXIT_FAILURE
: EXIT_SUCCESS);
}
void
usage(char *name)
{
fprintf(stderr, "usage: %s -s
source_ip -d destination_ip\n ", name);
}
/* EOF */
#include <libnet.h>
#define MAX_PAYLOAD_SIZE 1024
void usage(char *);
u_char enet_src[6] = {0x0d, 0x0e, 0x0a, 0x0d, 0x00,
0x00};
u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff,
0xff};
int
main(int argc, char *argv[])
{
int packet_size,
/* size of our packet */
payload_size,
/* size of our packet */
c;
/* misc */
u_long src_ip, dst_ip;
/* source ip, dest ip */
u_short bport, eport;
/* beginning and end ports */
u_short cport;
/* current port */
u_char payload[MAX_PAYLOAD_SIZE];
/* packet payload */
u_char *packet;
/* pointer to our packet buffer */
char err_buf[LIBNET_ERRBUF_SIZE];
/* error buffer */
u_char *device;
/* pointer to the device to use */
struct libnet_link_int *network;
/* pointer to link interface struct */
struct libnet_plist_chain plist;
/* plist chain */
struct libnet_plist_chain *plist_p;
/* plist chain pointer */
printf("libnet example code:\tmodule
4\n\n");
printf("packet injection interface:\tlink
layer\n");
printf("packet type:\t\t\tUDP
[with payload] using port list chaining\n");
plist_p = NULL;
device = NULL;
src_ip = 0;
dst_ip = 0;
HEY LOOK! We have another argument for the port list. Port lists must be specified as ranges delimited by dashes, with multiple ranges delimited by commas. See section 5 (support functions) for more information on port list chain syntax.
while ((c = getopt(argc, argv,
"i:d:s:p:")) != EOF)
{
switch
(c)
{
case 'd':
if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
{
libnet_error(LIBNET_ERR_FATAL,
"Bad destination IP address: %s\n", optarg);
}
break;
case 'i':
device = optarg;
break;
case 's':
if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
{
libnet_error(LIBNET_ERR_FATAL,
"Bad source IP address: %s\n", optarg);
}
break;
case 'p':
plist_p = &plist;
if (libnet_plist_chain_new(&plist_p, optarg) == -1)
{
libnet_error(LIBNET_ERR_FATAL, "Could not build port list\n");
}
break;
default:
usage(argv[0]);
exit(EXIT_FAILURE);
}
}
if (!src_ip || !dst_ip || !plist_p)
{
usage(argv[0]);
exit(EXIT_FAILURE);
}
We also require an argument for the packet payload. This code is probably not proof from overflows so take heed.
c = argc - optind;
if (c != 1)
{
usage(argv[0]);
exit(EXIT_FAILURE);
}
memset(payload, 0, sizeof(payload));
strncpy(payload, argv[optind],
strlen(argv[optind]));
/*
* Step 1: Network
Initialization (interchangable with step 2).
*/
if (device == NULL)
{
struct
sockaddr_in sin;
/*
* Try to locate a device.
*/
if (libnet_select_device(&sin,
&device, err_buf) == -1)
{
libnet_error(LIBNET_ERR_FATAL, "libnet_select_device failed: %s\n", err_buf);
}
printf("device:\t\t\t\t%s\n",
device);
}
if ((network = libnet_open_link_interface(device,
err_buf)) == NULL)
{
libnet_error(LIBNET_ERR_FATAL,
"libnet_open_link_interface: %s\n", err_buf);
}
/*
* Get the payload
from the user. Hrm. This might fail on a Sparc
* if byte alignment
is off...
*/
payload_size = strlen(payload);
/*
* We're going to build
a UDP packet with a payload using the
* link-layer API,
so this time we need memory for a ethernet header
* as well as memory
for the ICMP and IP headers and our payload.
*/
packet_size = LIBNET_IP_H + LIBNET_ETH_H
+ LIBNET_UDP_H + payload_size;
/*
* Step 2: Memory Initialization
(interchangable with step 1).
*/
if (libnet_init_packet(packet_size,
&packet) == -1)
{
libnet_error(LIBNET_ERR_FATAL,
"libnet_init_packet failed\n");
}
/*
* Step 3: Packet construction
(ethernet header).
*/
libnet_build_ethernet(enet_dst,
enet_src,
ETHERTYPE_IP,
NULL,
0,
packet);
/*
* Step 3: Packet construction
(IP header).
*/
libnet_build_ip(LIBNET_UDP_H +
payload_size,
0,
/* IP tos */
242,
/* IP ID */
0,
/* Frag */
64,
/* TTL */
IPPROTO_UDP,
/* Transport protocol */
src_ip,
/* Source IP */
dst_ip,
/* Destination IP */
NULL,
/* Pointer to payload (none) */
0,
packet + LIBNET_ETH_H); /* Packet header memory */
We run in a loop, grabbing port list ranges as we go. We only really need to update the UDP port and checksum portions of the packet, but for simplicity's sake, we'll lump it all together thusly...
while (libnet_plist_chain_next_pair(plist_p,
&bport, &eport))
{
Check to see if we've exhausted our cache of port list ranges.
while (!(bport
> eport) && bport != 0)
{
cport = bport++;
/*
* Step 3: Packet construction (UDP header).
*/
libnet_build_udp(242,
/* source port */
cport,
/* dest. port */
payload,
/* payload */
payload_size,
/* payload length */
packet + LIBNET_ETH_H + LIBNET_IP_H);
/*
* Step 4: Packet checksums (ICMP header *AND* IP header).
*/
if (libnet_do_checksum(packet + ETH_H, IPPROTO_UDP, LIBNET_UDP_H + payload_size)
== -1)
{
libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
}
if (libnet_do_checksum(packet + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1)
{
libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
}
/*
* Step 5: Packet injection.
*/
c = libnet_write_link_layer(network, device, packet, packet_size);
if (c < packet_size)
{
libnet_error(LN_ERR_WARNING, "libnet_write_link_layer only wrote %d bytes\n",
c);
}
else
{
printf("construction and injection completed, wrote all %d bytes, port
%d\n", c, cport);
}
}
}
/*
* Shut down the interface.
*/
if (libnet_close_link_interface(network)
== -1)
{
libnet_error(LN_ERR_WARNING,
"libnet_close_link_interface couldn't close the interface");
}
/*
* Free packet memory.
*/
libnet_destroy_packet(&packet);
return (c == -1 ? EXIT_FAILURE
: EXIT_SUCCESS);
}
void
usage(char *name)
{
fprintf(stderr, "usage: %s [-i
interface] -s s_ip -d d_ip -p port list payload\n", name);
}
/* EOF */