Next Previous Top


6. Sample applications


The following are some simple examples that highlight different areas of functionality offered by libnet.  Each one of these programs is autonomous and can be compiled into standalone executable.  We'll go through the first example step by step, to fully understand what's going on, then, as we progress to subsequent examples, we will cover only new or salient code.  Comments are clearly visible in red.

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`



6.1 Example 1 [raw socket api - TCP packet]
Download libnet-example-1.c

#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 */
 




6.2 Example 2 [link layer api - ICMP_MASK]
Download libnet-example-2.c
 

#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 */




6.3 Example 3 [raw socket api - ICMP_ECHO using an arena]
Download libnet-example-3.c

#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 */




6.4 Example 4 [link-layer api - UDP packet using port list chaining]
Download libnet-example-4.c

#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 */



Next Previous Top