Sunday, July 20, 2014

Installing and using libnet on the BeagleBone Black

My latest pet project has been building a robot with my daughter using the BeagleBone black.  You can see our robot on my robotics blog.  While I wait for a new part to arrive, I started wondering if I could install libnet and libpcap on the BeagleBone Black so I could write some network analysis tools that could run on it.  It turned out to be pretty straightforward.

If you are not familiar with the BeagleBone black or just getting started with it, you can take a look at the beagleboard.org site.  You can also take a look at my “I just got my beagleBone Black now what” post to see how I have my BeagleBone setup.

I started off by downloading the libnet library from http://sourceforge.net/projects/libnet-dev/.  Once the download was complete, I ran the following commands to install it:

gunzip libnet-1.2-rc3.tar.gz
tar –xvf libnet-1.2-rc3.tar
cd libnet libnet-1.2-rc3
./configure
make
make install

This will install the libnet header files to /usr/local/include and the libnet library files to /usr/local/lib.  You will need to set the LD_LIBRARY_PATH to include /usr/local/lib or copy the libnet library files from /usr/local/lib to /lib (I strongly recommend setting the LD_LIBRARY_PATH).  To set the LD_LIBRARY_PATH, I edited the /etc/profile file and added the following line near the end of the file:

export LD_LIBRARY_PATH=/usr/local/lib

To test the libnet installations we can use the same libnet library that I wrote in two earlier blog posts.  To save you from going back and forth between the two posts, I am reposting the code here but I will not re-explain it.  You can look at the posts if you want to review how the library works or want to review the network packet headers.  Here are the links to the posts:


Lets begin by looking at the libnet_lib.h file.  This is the header file for my custom libnet library to make injecting packets into the network very easy:

#include <sys/types.h>
#include <stdbool.h>

#ifndef LIBNET_LIB_H
#define LIBNET_LIB_H

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

#endif // LIBNET_LIB_H

Now lets look at the libnet_lib.c file.  This is the implementation of my custom libnet 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;
}

Now lets look at the main.c file that will create an ICMP Echo (ping) packet and a TCP packet.

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

int main(void)
{
    printf("ICMP!\n");
    bool success = sendICMPEcho("10.0.1.4", "Hello from libnet", ICMP_ECHO, "eth0");
    if (success) {
        printf("Success");
    } else {
        printf("Failed");
    }
   
    printf("\nTCP\n");
    bool success1 = sendTCP("10.0.1.4", 3535, TH_SYN|TH_ACK,"Hello from libnet","eth0");
    if (success1) {
        printf("Success1");
    } else {
        printf("Failed1");
    }

    return 0;
}

To compile this we run the following command:

gcc -I/usr/local/include -o  libnettest -lnet libnet_lib.c main.c

If all is well we should have a libnettest executable.  If you run libnettest, you should see output that is similar to this:



To verify that the packets went out correctly, you can run Wireshark (http://www.wireshark.org) on the host that you are sending the packets too.


Libnet is a very powerful library that can allow you to write several really cool networking tools especially if you combine libnet with libpcap (packet capture library).  One of my favorite tools that I have wrote was a heartbeat application that was written in Java using jpcap.  This application would send out a bad TCP packet and if it received a reset packet back from the host, it knew the host was alive.  I wrote an article about the application and it was published in the September 2006 edition of the Unix Sys Admin magazine.