Saturday, July 26, 2014

RSNetworking – Major Update

I recently wrote an iOS communication library for the SparkCore in Objective-C and it gave me some great ideas on how the RSNetworking library could work.  I have updated the RSNetworking library to include my ideas and will be depreciating the original RSNetworking class soon.  After trying the new library out with the sample project, I am really excited about the update.  Please let me know what you think of the changes and any ideas that you may have.  You can find the code, with a sample application on GitHub here:  https://github.com/hoffmanjon/RSNetworking

While the original RSNetworking class is still in the library, I have put notes in the class that it will be going away soon.  Instead I moved the dataFromURL, stringFromURL, dictionaryFromURL, and imageFromURL functions to the new RSURLRequest class.  You can use these functions exactly like you used them before.  Eventually I would like to make these functions class (static) functions but it does not appear that the class (static) functionally is fully implemented yet (as of beta 4) since I cannot define class variables yet.

The isHostnameReachable function has moved to the RSUtilities class.  The RSUtilities class will contain various utilities.  Currently the isHostnameReachable function is the only function defined in the RSUtilities class.

Now we come to the big changes in the library.  These changes are part of two classes.  These are the RSTransaction and RSTransactionRequest classes.  Lets look at how we would use them to submit a GET request to Apple’s iTunes search API:

//initilate the RSTransactionRequest()
        var rsRequest = RSTransactionRequest()
       
//Define a RSTranaction object
        var rsTransGet = RSTransaction(transactionType: RSTransactionType.GET, baseURL: "https://itunes.apple.com", path: "search", parameters: ["term":"jimmy+buffett","media":"music"])
       
   
//Call the dictionaryFromRSTransaction function to make the request to the iTunes search API using the RSTransaction we created
        rsRequest.dictionaryFromRSTransaction(rsTransGet, completionHandler: {(response : NSURLResponse!, responseDictionary: NSDictionary!, error: NSError!) -> Void in
            if !error? {
                     println(responseDictionary)
            } else {
                //If there was an error, log it
                println("Error : \(error)")
            }
            })

We begin by initializing a RSTransactionRequest object.  Eventually I would like to make the functions in RSTransactionRequest class (static) functions but, like I noted above, the class (static) functionality does not look complete yet. 

Once we have the RSTransactionRequest object, we then create an RSTransaction object using the init(transactionType: RSTransactionType, baseURL: String,  path: String, parameters: [String: String]) initializer.  The RSTransaction class is designed to contain everything needed to create a request to a HTTP web service.  We then use the dictionaryFromRSTransaction function from the RSTransactionRequest object, passing in the RSTransaction object, to make the web service call.

What makes this so nice is we can now simply update the parameters of the RSTransaction class like this:

rsTransGet.parameters = ["term":"jimmy","media":"music"]

Then we can resubmit the RSTransaction to make another call. This will allow use to have numerous web services configured but we will only need one instance of the RSTransactionRequest class.  This will really become evident when we can make the functions in the RSTransactionRequest class, class (static) functions.

Lets take a look at how we would submit a POST request using the posttestserver.com site.  To make this request we use the same RSTransactionRequest object (rsRequest) that we used to make the GET request to Apple’s iTunes search API.  Here is the code:

//Post request
var rsTransPost = RSTransaction(transactionType: RSTransactionType.POST, baseURL: "https://posttestserver.com", path: "post.php", parameters: ["key":"value","key2":"value2"])
       
//Call the stringFromRSTrasaction function to make the request to posttestserver.com
rsRequest.stringFromRSTransaction(rsTransPost, completionHandler: {(response : NSURLResponse!, responseString: NSString!, error: NSError!) -> Void in
        if !error? {
            //Log response string
            println(responseString)
        } else {
            //If there was an error, log it
            println("Error : \(error)")
        }
       })
As you can see, the POST requests is exactly like the GET requests except we changed the transactionType parameter to RSTransactionType.POST instead of RSTransactionType.GET.

The RSTransaction class exposes four properties, one initiator and one method.  These are:
- Properties
* TransactionType - This defines the HTTP request method.  Currently there are three types, GET, POST, UNKNOWN.  Only the GET and POST actually sends a request.
* baseURL - This is the base URL to use for the request.  This will normally look something like this:  "https://itunes.apple.com".  If you are going to a non-standard port you would put that here as well.  It would look something like this:  "http://mytestserver:8080"
*path - The path that will be added to the base url.  This will normally be something like this: "search".  It can also include a longer path string like: "path/to/my/service"
* parameters - Any parameters to send to the service.
- Initiators
* init(transactionType: RSTransactionType, baseURL: String,  path: String, parameters: [String: String]) - This will initialize the RSTransaction with all properties needed.
- Function
* getFullURLString() -> String - Builds and returns the full URL needed to connect to the service.

The RSTransactionRequest contains exposes four functions.  These are:
* dataFromRSTransaction(transaction: RSTransaction, completionHandler handler: RSNetworking.dataFromRSTransactionCompletionCompletionClosure):
 Retrieves an NSData object from the service defined by the RSTransaction.  This is the main function and is used by the other three functions to retrieve an NSData object prior to converting it to the required format.

* stringFromRSTransaction(transaction: RSTransaction, completionHandler handler:  RSNetworking.stringFromRSTransactionCompletionCompletionClosure):  
Retrieves an NSString object from the service defined by the RSTransaction.  This function uses the dataFromRSTransaction function to retrieve an NSData object and then converts it to an NSString object.

*dictionaryFromRSTransaction(transaction: RSTransaction, completionHandler handler:  RSNetworking.dictionaryFromRSTransactionCompletionCompletionClosure):
 Retrieves an NSDictionary object from the service defined by the RSTransaction.  This function uses the dataFromRSTransaction function to retrieve an NSData object and then converts it to an NSDictionary object.  The data returned from the URL should be in JSON format for this function to work properly.

*imageFromRSTransaction(transaction: RSTransaction, completionHandler handler:  RSNetworking.imageFromRSTransactionCompletionCompletionClosure):
Retrieves an UIImage object from the service defined by the RSTransaction.  This function uses the dataFromRSTransaction function to retrieve an NSData object and then converts it to an UIImage object.

Hopefully others will find this library useful.  To receive notifications when the RSNetworking library is updated, please subscribe to my twitter feed.  You can download the code from GitHub here:  https://github.com/hoffmanjon/RSNetworking


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.