Using libnetdude

Table of Contents
Building libnetdude
Installation Layout
The lndtool Program
Building Applications with libnetdude
libnetdude's Testsuite

This chapter explains how to build libnetdude, what parts of libnetdude end up where on your system when you install it, and how to build other programs that use libnetdude.


Building libnetdude

Building libnetdude will hopefully be easy. libnetdude has two dependencies, make sure these are installed before you try to build your copy:

The build itself is made using the common ./configure && make && make install sequence. Check ./configure --help for a list of available options, particularly the --with-pcapnav... options to specify a libpcapnav that's installed in an unusual location.


Installation Layout

The installation places files in the following locations (the full path depends on what --prefix option you passed to configure. The default value is /usr/local):


The lndtool Program

libnetdude comes with a tool for querying the local libnetdude installation: lndtool. Have a look at its command line options:
lndtool -- libnetdude configuration and execution tool.
USAGE: lndtool [OPTIONS]

  --help, -help, -h, -?        This message.
  --prefix                     Installation prefix.
  --version, -v                Prints out version info.
  --cflags                     Preprocessor flags needed for compilation.
  --libs                       Linker flags needed when linking..
  --plugin-dir                 Plugin installation directory.
  --proto-dir                  Protocol installation directory.
  --include-dir                Header files directory.
  --plugins                    Lists all plugins that register successfully.
  --run, -r PLUGINNAME PARAMS  Run plugin PLUGINNAME with PARAMS.
        
As you can see, most of the options look familiar from package configuration scripts normally called <package>-config. libnetdude uses a separate program (and it is a binary executale, not a shell script) because in the case of libnetdude you may want to query settings that require libnetdude to be loaded and initialized, such as listing the installed plugins. lndtool behaves just like a libnetdude-config would, but has two additional features:


Building Applications with libnetdude

In this section, we'll first look at how you can check for libnetdude in autoconf scripts. Then we get a bit technical and explain how linking to the library and its plugins works.


Handy autoconf Code

If you are using the autoconf/automake tools to configure your package, use the following check to detect libnetdude:
dnl ##################################################
dnl # Check for libnetdude
dnl ##################################################
AC_ARG_WITH(lndtool,
    AC_HELP_STRING([--with-lndtool=FILE], [Use given lndtool]),
    [ lndtool="$withval" ],
    [ AC_PATH_PROG(lndtool, lndtool,
                   AC_MSG_ERROR(Cannot find lndtool: is it in path?)) ])

LIBNETDUDE_CFLAGS=`$lndtool --cflags`
LIBNETDUDE_LIBS=`$lndtool --libs`
AC_SUBST(LIBNETDUDE_LIBS)
AC_SUBST(LIBNETDUDE_CFLAGS)
# same for any other options you require ...
          
You can then use the compiler/linker flags that libnetdude requires in your Makefile.am using @LIBNETDUDE_CFLAGS@ and @LIBNETDUDE_LIBS@.

Note

Using the output of lndtool --cflags|--libs provides all the compiler/linker flags you need to pull in the dependencies (libpcapnav and glib). You do not need to add extra checks and flags for those dependancies in your build scripts.


Linking with libnetdude and its Plugins

Let's assume you are writing a program that uses libnetdude and you want to link your compiled object files with libnetdude (we assume shared libraries here). If your program uses only symbols (functions, globals, etc) from libnetdude itself, this is not a problem: you simply use the linker flags provided by lndtool --libs. However, if you are using symbols from plugins, things are more tricky. Say we have a plugin called Boofar that defines functions libnd_boofar_foo(LND_Trace *) and libnd_boofar_bar(LND_Trace *) in a header file called libnd_boofar.h. Consider the following code that opens a trace file passed on the command line (without error checking, shame on them), and then passes the opened trace to these two functions before closing the trace.
#include <libnd.h>
#include <plugins/libnd_boofar.h>

int 
main(int argc, char **argv)
{
  LND_Trace *trace;

  libnd_init();

  trace = libnd_trace_new(argv[0]);
  libnd_boofar_foo(trace);
  libnd_boofar_bar(trace);
  libnd_trace_free(trace);

  return 0;
}
          
At build time, the necessary declarations are taken from the plugin's header files (found because we pass the output of lndtool --cflags to the compiler), so the compilation completes fine. However, when you try linking your program, you will get something like this:
/tmp/ccnIJufv.o(.text+0xa6): In function `main':
: undefined reference to `libnd_boofar_foo'
/tmp/ccnIJufv.o(.text+0xc0): In function `main':
: undefined reference to `libnd_boofar_foo'
          
The problem is that the Boofar plugin is loaded dynamically when libnetdude bootstraps, hence the plugin's symbols are not found when linking. There are two possible solutions to this problem:

  • Pass the plugin's shared object file when linking. This is ugly for a number of reasons. You need to know the names of Boofar's binary files. You need to make sure that your executable will find them when it starts (likely using --rpath magic). Passing the plugin binaries to the linker does not make sense, since libnetdude will dynamically link in the plugins when initialized. Worst of all, you also need to pass the binary files of any other plugins that Boofar requires.

    In the end this approach boils down to passing all installed plugin binaries to the linker, defeating the intention of the plugins. This approach therefore is not acceptable.

  • Do not link your code into a standalone executable. This sounds odd, but when you link the code into a shared executable, the linker will not complain about unresolved symbols and defer the linking until runtime. In short, your program becomes another plugin, which is exactly the purpose of libnetdude's modular design. To run your program, you then use a wrapper program that calls your plugin on your behalf. Remember lndtool --run, described in the previous section? Now you know its purpose.

Let's see how this works. We change the code to have a minimalistic but valid libnetdude feature plugin structure:
#include <libnd.h>
#include <plugins/libnd_boofar.h>

const char *
name(void)
{
  return "Boofar-App";
}

gboolean
run(LND_Trace *unused, LND_PluginArgs *args)
{
  LND_Trace *trace;

  printf("Opening trace file %s.\n", trace->filename);
  trace = libnd_trace_new(args->argv[0]);
  libnd_boofar_foo(trace);
  libnd_boofar_bar(trace);
  libnd_trace_free(trace);

  return TRUE;
}
          
Now you compile and link this code as a libnetdude plugin, for example using the code template provided on the SourceForge site. Otherwise there is no difference: your build environment will have to check for libnetdude anyway. The linker does not find the Boofar symbols, but this time it does not complain. After installing the plugin, you can then run your app using lndtool like this:
lndtool --run Boofar-App mytracefile.trace
Opening trace file mytracefile.trace.
          
If you find this too cumbersome, wrap the call in a shell script as often done with Java applications and there's no visible difference.


libnetdude's Testsuite

Should you decide to delve into hacking libnetdude itself (yay!), you'll want to have a look at the contents of the test directory in the source tree. It contains a few programs that can be built using make tests and that are not installed. These programs are: