Google

NAME="GENERATOR" CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+ ">

Extending Netdude

Netdude is designed to provide a core set of functionality upon which protocol and feature support can be built in a modularized fashion. The mechanism used to achieve this is the dynamic linker library, libdl. Well actually it's the libtool wrapper, libltdl [Libtool], to keep life simple. Therefore, Netdude plugins come as platform-dependant normal binary code in shared libraries. They're not interpreted scripts.

When Netdude starts, it scans specific directories for plugins, dynamically opens them and looks for special symbols, actually hooks that provide callback implementations. The plugins are then initialized and hooked into the GUI as menu entries etc. The directories Netdude looks at can always be obtained by issuing the following commands, either at the command line or in your build scripts:

  • netdude --plugindir: this outputs the system-wide directory in which feature plugins are installed.

  • netdude --protodir: this outputs the system-wide directory in which protocol plugins are installed.

Usually the names will be /usr/share/netdude/plugins and /usr/share/netdude/protocols, or the /usr/local versions thereof. To allow users to install plugins privately, the directories ~/.nd/plugins and ~/.nd/protocols can also be used.

In order to compile new code using the Netdude API, you'll need to include Netdude's header files. You can obtain the directory in which Netdude's header files are installed using the command netdude --includedir. If you add that directory to the include path of your build environment (that's already done for you in the code templates), you can then access the header files as in the following example.

#include <netdude/nd_packet.h>
    

You can always check if a plugin was loaded correctly by looking at Netdude's About menu, which will list the loaded plugins and display info dialogs about them upon request:

Netdude's About menu.


Writing A Plugin

Why would one want to write a Netdude feature plugin? Well, Netdude plugins basically only need to provide one big hook that serves as the entry point into the plugin. In that callback implementation, the plugin can do anything the author desires -- iterate over packets, manipulate packets, gather statistics, etc.

Writing a feature plugin for Netdude is easy, assuming you have reasonable knowledge of the Netdude API (see also the API documentation). If you don't have an existing codebase for Netdude plugins, I suggest you start by downloading the Netdude plugin code template, available from the Netdude download page.

Extract the tarball. If you want to keep multiple plugins in your package, add a directory for each one and update configure.ac/configure.in and the Makefile.ams accordingly. Details of handling the auto* tools are beyond the scope of this document, please consult the appropriate documentation [Autoconf] [Automake]. If you feel you're in trouble, please ask for help on the Netdude mailing lists. For the rest of this section we'll assume that you have a working build environment for your plugin(s).

The following piece of code, taken from nd_plugin.h, lists the callbacks you can provide in your plugin. You may leave out some if you wish, they all get initialized to no-ops by default.

typedef struct nd_plugin
{
  const char *(*name) (void);
  const char *(*description) (void);
  const char *(*author) (void);
  const char *(*version) (void);

  int         (*run) (ND_Trace *trace);

  char        *filename;
  lt_dlhandle  lt;

} ND_Plugin;
  

You don't need to worry about filename and lt, they're used internally by Netdude. The other function pointers are pretty much self-explanatory:

  • name: implement this function by returning a string containing the name of your plugin. This is the string that will show up in Netdude's menus.

  • description: implement this function by returning a string containing a brief description of your plugin. Don't forget to add the gettext macros around it, so that it can be translated.

  • author: implement this function by returning a string containing the plugin author's name.

  • version: implement this function by returning a string containing the plugin's version number.

  • run: this is where the bread meets the butter. This callback is called when you click on your plugin's menu item. It receives the currently edited trace as the only parameter. Inside that function, you can do whatever you need to provide the functionality intended.

Caution

You must use the names given above for these hooks, otherwise Netdude won't find them when scanning the plugins!

Netdude comes with a simple demo plugin that corrects all checksums in the currently selected packets. See plugins/nd_cksumfix.c in the Netdude source tarball. Its code is short enough to be given here in all its glory:


#include <netdude/nd.h>
#include <netdude/nd_gettext.h>
#include <netdude/nd_packet_iterator.h>
#include <netdude/nd_packet.h>
#include <netdude/nd_protocol.h>

/* The Checksum Fix plugin. It calls the fix_packet()
 * callback for all protocols existing in the active
 * packets (i.e. all packets if select-to-all mode is
 * active, or just the selected ones, otherwise).
*/

typedef struct nd_cksum_data
{
  int          tested;
  int          modified;
  int          index;
  gboolean     changed;
} ND_CksumData;


const char *
name(void)
{
  return _("Checksum Fix Plugin");
}


const char *
description(void)
{
  return _("The Checksum Fix plugin. It fixes the headers of "
	   "all protocols in the packets the plugin is applied "
	   "to. The actual functionality depends on the way "
	   "the protocols implement it.");
}


const char *
author(void)
{
  return _("Christian Kreibich, <christian AT whoop.org>");
}


const char *
version(void)
{
  return _("0.1.0");
}


static void
fix_packet_cb(ND_Packet *p, ND_ProtoData *pd, void *user_data)
{
  ND_CksumData *data = (ND_CksumData *) user_data;

  if (!p || !pd)
    return;

  /* Fix up the protocol data, depending on how the
   * protocol plugin implements that operation.
   * If the packet was modified, set a flag to let our
   * called know about it.
   */
  if (pd->inst.proto->fix_packet(p, data->index))
    data->changed = TRUE;
}

void
run(ND_Trace *trace)
{
  ND_PacketIterator  pit;
  ND_CksumData       data;
  char               message[MAXPATHLEN];

  /* Initialize our helper struct: */
  memset(&data, 0, sizeof(ND_CksumData));
  
  /* Use a packet iterator for selected packets on the given trace */
  for (nd_pit_init(&pit, trace, TRUE); nd_pit_get(&pit); nd_pit_next(&pit))
    {
      /* Update our data structure -- we maintain
       * investigated and modified packets.
       */
      data.index = nd_pit_get_index(&pit);
      data.tested++;
      data.changed = FALSE;

      /* Iterate over the protocols contained in the packet,
       * from inner- to outermost, and call our callback for
       * each protocol which will then correct any checksums.
       */
      nd_packet_foreach_proto_backward(nd_pit_get(&pit),
				       fix_packet_cb,
				       &data);

      if (data.changed)
	data.modified++;
    }

  /* Some GUI candy to let the user see what's going on */
  g_snprintf(message, MAXPATHLEN, _("%i packets checked, %i fixed."),
	     data.tested, data.modified);

  nd_gui_statusbar_set(message);
}