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:
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:
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.
 | 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);
}
|