Bring developer guide up to date regarding tools and current plugin build infrastructure.

svn path=/trunk/; revision=22117
This commit is contained in:
Jaap Keuter 2007-06-17 11:18:29 +00:00
parent 162382dcb1
commit 8c241db91e
4 changed files with 118 additions and 226 deletions

View File

@ -45,7 +45,7 @@ DOCUMENT SECTION
<!--
Wireshark Info
-->
<!ENTITY WiresharkCurrentVersion "0.99.5">
<!ENTITY WiresharkCurrentVersion "0.99.6">
<!ENTITY WiresharkWebSite "http://www.wireshark.org">
<!ENTITY WiresharkDownloadPage "&WiresharkWebSite;/download/">
<!ENTITY WiresharkAuthorsPage "http://anonsvn.wireshark.org/wireshark/trunk/AUTHORS">

View File

@ -57,14 +57,12 @@
With a little care, the plugin can be made to run as a built in
easily too - so we haven't lost anything.
</para>
<example><title>Basic Plugin setup.</title>
<programlisting>
<![CDATA[
#ifdef HAVE_CONFIG_H
<example><title>Dissector Initialisation.</title>
<programlisting>
<![CDATA[#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gmodule.h>
#include <epan/packet.h>
#include <epan/prefs.h>
@ -73,82 +71,14 @@ void proto_register_foo();
void proto_reg_handoff_foo();
void dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
/* Define version if we are not building Wireshark statically */
#ifndef ENABLE_STATIC
G_MODULE_EXPORT const gchar version[] = "0.0";
#endif
static int proto_foo = -1;
static int global_foo_port = 1234;
static dissector_handle_t foo_handle;
#ifndef ENABLE_STATIC
G_MODULE_EXPORT void
plugin_register(void)
{
/* register the new protocol, protocol fields, and subtrees */
if (proto_foo == -1) { /* execute protocol initialization only once */
proto_register_foo();
}
}
G_MODULE_EXPORT void
plugin_reg_handoff(void){
proto_reg_handoff_foo();
}
#endif]]>
</programlisting>
</example>
<para>
Lets go through this a bit at a time. First we have some boiler plate
include files. These will be pretty constant to start with. Here we also
pre-declare some functions that we'll be writing shortly.
</para>
<para>
Next we have a section surrounded by #ifdef ENABLE_STATIC. This is what
makes this a plugin rather than a built in dissector.
</para>
<para>
The version is a simple string that is used to report on the version of this
dissector. You should increase this number each time you make changes that you
need to keep track of.
</para>
<para>
Next we have an int that is initialised to -1 that records our protocol.
This will get updated when we register this plugin with the main program.
We can use this as a handy way to detect if we've been initialised yet.
Its good practice to make all variables and functions that aren't exported
static to keep name space pollution. Normally this isn't a problem unless your
dissector gets so big it has to span multiple files.
</para>
<para>
Then a global variable which contains the UDP port that we'll assume we are dissecting traffic for.
</para>
<para>
Next a dissector reference that we'll initialise later.
</para>
<para>
Next, the first plugin entry point. The function plugin_register() is called
when the plugin is loaded and allows you to do some initialisation stuff,
which will include communicating with the main program what you're plugins
capabilities are.
</para>
<para>
The plugin_reg_handoff routine is used when dissecting sub protocols. As our
hypothetical protocol will be hypothetically carried over UDP then we will
need to do this.
</para>
<para>
Now we have the basics in place to interact with the main program, we had
better fill in those missing functions. Lets start with register function.
</para>
<example><title>Plugin Initialisation.</title>
<programlisting>
<![CDATA[void
void
proto_register_foo(void)
{
module_t *foo_module;
if (proto_foo == -1) {
proto_foo = proto_register_protocol (
"FOO Protocol", /* name */
@ -156,29 +86,49 @@ proto_register_foo(void)
"foo" /* abbrev */
);
}
foo_module = prefs_register_protocol(proto_foo, proto_reg_handoff_foo);
}]]>
}]]>
</programlisting></example>
<para>
First a call to proto_register_protocol that
registers the protocol. We can give it three names that
will be used in various places to display it.
- XXX explain where, this can be confusing
Lets go through this a bit at a time. First we have some boiler plate
include files. These will be pretty constant to start with. Here we also
pre-declare some functions that we'll be writing shortly.
</para>
<para>
Then we call the preference register function. At the moment we have
no specific protocol preferences so this will be all that we need.
This takes a function parameter which is our handoff function.
I guess we'd better write that next.
Next we have an int that is initialised to -1 that records our protocol.
This will get updated when we register this dissector with the main program.
We can use this as a handy way to detect if we've been initialised yet.
Its good practice to make all variables and functions that aren't exported
static to keep name space pollution down. Normally this isn't a problem unless your
dissector gets so big it has to span multiple files.
</para>
<example><title>Plugin Handoff.</title>
<para>
Then a module variable which contains the UDP port that we'll assume we are dissecting traffic for.
</para>
<para>
Next a dissector reference that we'll initialise later.
</para>
<para>
Now we have the basics in place to interact with the main program, we had
better fill in those missing functions. Lets start with register function.
</para>
<para>
First a call to proto_register_protocol that registers the protocol.
We can give it three names that will be used in various places to display it.
The full and short name are used in the eg. the "Preferences" and "Enabled protocols"
dialogs as well as the generated field name list in the documentation.
The abbreviation is used as display filter name.
</para>
<para>
Next we need a handoff routine.
</para>
<example><title>Dissector Handoff.</title>
<programlisting>
<![CDATA[void
proto_reg_handoff_foo(void)
{
static int Initialized=FALSE;
static int initialized=FALSE;
if (!Initialized) {
if (!initialized) {
foo_handle = create_dissector_handle(dissect_foo, proto_foo);
dissector_add("udp.port", global_foo_port, foo_handle);
}
@ -196,7 +146,7 @@ proto_reg_handoff_foo(void)
Now at last we finally get to write some dissecting code. For the moment we'll
leave it as a basic placeholder.
</para>
<example><title>Plugin Dissection.</title>
<example><title>Dissection.</title>
<programlisting>
<![CDATA[static void
dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
@ -230,68 +180,39 @@ dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
<para>
At this point we should have a basic dissector ready to compile and install.
It doesn't do much at present, than identify the protocol and label it.
Compile the dissector to a dll or shared library, and copy it into the plugin
directory of the installation. To finish this off a Makefile of some sort will be
required. A Makefile.nmake for Windows platforms and a Makefile.am for unix/linux
types.
</para>
<example><title>Makefile.nmake for Windows.</title>
<programlisting>
<![CDATA[
include ..\..\config.nmake
############### no need to modify below this line #########
CFLAGS=/DHAVE_CONFIG_H /I../.. /I../../wiretap $(GLIB_CFLAGS) \
/I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS)
LDFLAGS = /NOLOGO /INCREMENTAL:no /MACHINE:I386 $(LOCAL_LDFLAGS)
!IFDEF ENABLE_LIBWIRESHARK
LINK_PLUGIN_WITH=..\..\epan\libwireshark.lib
CFLAGS=/DHAVE_WIN32_LIBWIRESHARK_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS)
OBJECTS=foo.obj
foo.dll foo.exp foo.lib : $(OBJECTS) $(LINK_PLUGIN_WITH)
link -dll /out:foo.dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \
$(GLIB_LIBS)
!ENDIF
clean:
rm -f $(OBJECTS) foo.dll foo.exp foo.lib *.pdb
distclean: clean
maintainer-clean: distclean]]>
</programlisting></example>
<example><title>Makefile.am for unix/linux.</title>
<programlisting>
<![CDATA[
INCLUDES = -I$(top_srcdir)
plugindir = @plugindir@
plugin_LTLIBRARIES = foo.la
foo_la_SOURCES = foo.c moduleinfo.h
foo_la_LDFLAGS = -module -avoid-version
foo_la_LIBADD = @PLUGIN_LIBS@
# Libs must be cleared, or else libtool won't create a shared module.
# If your module needs to be linked against any particular libraries,
# add them here.
LIBS =
CLEANFILES = \
foo \
*~
EXTRA_DIST = \
Makefile.nmake
]]>
</programlisting></example>
<para>
In order to compile this dissector and create a plugin a couple of support files
are required, besides the dissector source in packet-foo.c:
<itemizedlist>
<listitem><para>
Makefile.am - This is the UNIX/Linux makefile template
</para></listitem>
<listitem><para>
Makefile.common - This contains the file names of this plugin
</para></listitem>
<listitem><para>
Makefile.nmake - This contains the Wireshark plugin makefile for Windows
</para></listitem>
<listitem><para>
moduleinfo.h - This contains plugin version info
</para></listitem>
<listitem><para>
moduleinfo.nmake - This contains DLL version info for Windows
</para></listitem>
<listitem><para>
packet-foo.c - This is your dissector source
</para></listitem>
<listitem><para>
plugin.rc.in - This contains the DLL resource template for Windows
</para></listitem>
</itemizedlist>
You can find a good example for these files in the h223 plugin directory. Makefile.common
and Makefile.am have to be modified to reflect the relevant files and dissector name.
moduldeinfo.h and moduleinfo.nmake have to be filled in with the version information.
Compile the dissector to a DLL or shared library and copy it into the plugin
directory of the installation.
</para>
</section>
<section id="ChDissectDetails">
@ -313,8 +234,7 @@ EXTRA_DIST = \
</para>
<example><title>Plugin Packet Dissection.</title>
<programlisting>
<![CDATA[
static void
<![CDATA[static void
dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
@ -355,7 +275,7 @@ dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
This needs some changes to proto_register_foo. First a couple of statically
declare arrays.
</para>
<example><title>Plugin Registering data structures.</title>
<example><title>Registering data structures.</title>
<programlisting>
<![CDATA[static hf_register_info hf[] = {
{ &hf_foo_pdu_type,
@ -374,7 +294,7 @@ static gint *ett[] = {
<para>
Then, after the registration code, we register these arrays.
</para>
<example><title>Plugin Registering data structures.</title>
<example><title>Registering data structures.</title>
<programlisting>
<![CDATA[proto_register_field_array(proto_foo, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));]]>
@ -383,7 +303,7 @@ static gint *ett[] = {
The variables hf_foo_pdu_type and ett_foo also need to be declared
somewhere near the top of the file.
</para>
<example><title>Plugin data structure globals.</title>
<example><title>Dissector data structure globals.</title>
<programlisting>
<![CDATA[
static int hf_foo_pdu_type = -1;
@ -394,18 +314,16 @@ static gint ett_foo = -1;
<para>
Now we can enhance the protocol display with some detail.
</para>
<example><title>Plugin starting to dissect the packets.</title>
<example><title>Dissector starting to dissect the packets.</title>
<programlisting>
<![CDATA[
if (tree) { /* we are being asked for details */
<![CDATA[if (tree) { /* we are being asked for details */
proto_item *ti = NULL;
proto_tree *foo_tree = NULL;
ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);
foo_tree = proto_item_add_subtree(ti, ett_foo);
proto_tree_add_item(foo_tree, hf_foo_pdu_type, tvb, 0, 1, FALSE);
}
]]>
}]]>
</programlisting></example>
<para>
Now the dissection is starting to look more interesting. We have picked apart
@ -459,10 +377,9 @@ static gint ett_foo = -1;
Now lets finish off dissecting the simple protocol. We need to add a few
more variables to the hf array, and a couple more procedure calls.
</para>
<example><title>Plugin wrapping up the packet dissection.</title>
<example><title>Wrapping up the packet dissection.</title>
<programlisting>
<![CDATA[
static int hf_foo_flags = -1;
<![CDATA[static int hf_foo_flags = -1;
static int hf_foo_sequenceno = -1;
static int hf_foo_initialip = -1;
...
@ -492,8 +409,7 @@ static int hf_foo_initialip = -1;
proto_tree_add_item(foo_tree, hf_foo_pdu_type, tvb, offset, 1, FALSE); offset += 1;
proto_tree_add_item(foo_tree, hf_foo_flags, tvb, offset, 1, FALSE); offset += 1;
proto_tree_add_item(foo_tree, hf_foo_sequenceno, tvb, offset, 2, FALSE); offset += 2;
proto_tree_add_item(foo_tree, hf_foo_initialip, tvb, offset, 4, FALSE); offset += 4;
]]>
proto_tree_add_item(foo_tree, hf_foo_initialip, tvb, offset, 4, FALSE); offset += 4;]]>
</programlisting></example>
<para>
This dissects all the bits of this simple hypothetical protocol. We've introduced a new
@ -510,14 +426,12 @@ static int hf_foo_initialip = -1;
</para>
<example><title>Naming the packet types.</title>
<programlisting>
<![CDATA[
static const value_string packettypenames[] = {
<![CDATA[static const value_string packettypenames[] = {
{ 1, "Initialise" },
{ 2, "Terminate" },
{ 3, "Data" },
{ 0, NULL }
};
]]>
};]]>
</programlisting></example>
<para>
This is a handy data structure that can be used to look up value to names.
@ -527,14 +441,12 @@ static const value_string packettypenames[] = {
</para>
<example><title>Adding Names to the protocol.</title>
<programlisting>
<![CDATA[
{ &hf_foo_pdu_type,
<![CDATA[{ &hf_foo_pdu_type,
{ "FOO PDU Type", "foo.type",
FT_UINT8, BASE_DEC,
VALS(packettypenames), 0x0,
NULL, HFILL }
}
]]>
}]]>
</programlisting></example>
<para>
This helps in deciphering the packets, and we can do a similar thing for the
@ -542,8 +454,7 @@ static const value_string packettypenames[] = {
</para>
<example><title>Adding Flags to the protocol.</title>
<programlisting>
<![CDATA[
#define FOO_START_FLAG 0x01
<![CDATA[#define FOO_START_FLAG 0x01
#define FOO_END_FLAG 0x02
#define FOO_PRIORITY_FLAG 0x04
@ -573,8 +484,7 @@ static int hf_foo_priorityflag = -1;
proto_tree_add_item(foo_tree, hf_foo_flags, tvb, offset, 1, FALSE);
proto_tree_add_item(foo_tree, hf_foo_startflag, tvb, offset, 1, FALSE);
proto_tree_add_item(foo_tree, hf_foo_endflag, tvb, offset, 1, FALSE);
proto_tree_add_item(foo_tree, hf_foo_priorityflag, tvb, offset, 1, FALSE); offset += 1;
]]>
proto_tree_add_item(foo_tree, hf_foo_priorityflag, tvb, offset, 1, FALSE); offset += 1;]]>
</programlisting></example>
<para>
Some things to note here. For the flags, as each bit is a different flag, we use
@ -624,9 +534,7 @@ dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
val_to_str(packet_type, packettypenames, "Unknown (0x%02x)"));
foo_tree = proto_item_add_subtree(ti, ett_foo);
proto_tree_add_item(foo_tree, hf_foo_pdu_type, tvb, offset, 1, FALSE);
offset += 1;
...
]]>
offset += 1;]]>
</programlisting></example>
<para>
So here, after grabbing the value of the first 8 bits, we use it with one of the
@ -752,8 +660,7 @@ dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
followed by an ID of the sequence and a packet sequence number.
</para>
<programlisting>
<![CDATA[
msg_pkt ::= SEQUENCE {
<![CDATA[msg_pkt ::= SEQUENCE {
.....
flags ::= SEQUENCE {
fragment BOOLEAN,
@ -763,13 +670,11 @@ msg_pkt ::= SEQUENCE {
msg_id INTEGER(0..65535),
frag_id INTEGER(0..65535),
.....
}
]]>
}]]>
</programlisting>
<example><title>Reassembling fragments - Part 1</title>
<programlisting>
<![CDATA[
#include <epan/reassemble.h>
<![CDATA[#include <epan/reassemble.h>
...
save_fragmented = pinfo->fragmented;
flags = tvb_get_guint8(tvb, offset); offset++;
@ -786,8 +691,7 @@ if (flags & FL_FRAGMENT) { /* fragmented */
msg_reassembled_table, /* list of reassembled messages */
msg_num, /* fragment sequence number */
tvb_length_remaining(tvb, offset), /* fragment length - to the end */
flags & FL_FRAG_LAST); /* More fragments? */
]]>
flags & FL_FRAG_LAST); /* More fragments? */]]>
</programlisting></example>
<para>
We start by saving the fragmented state of this packet, so we can restore it later.
@ -876,8 +780,7 @@ pinfo->fragmented = save_fragmented;
</para>
<example><title>Reassembling fragments - Initialisation</title>
<programlisting>
<![CDATA[
static GHashTable *msg_fragment_table = NULL;
<![CDATA[static GHashTable *msg_fragment_table = NULL;
static GHashTable *msg_reassembled_table = NULL;
@ -886,8 +789,7 @@ msg_init_protocol(void)
{
fragment_table_init (&msg_fragment_table);
reassembled_table_init(&msg_reassembled_table);
}
]]>
}]]>
</programlisting></example>
<para>
First a couple of hash tables are declared, and these are initialised
@ -901,8 +803,7 @@ msg_init_protocol(void)
</para>
<example><title>Reassembling fragments - Data</title>
<programlisting>
<![CDATA[
...
<![CDATA[...
static int hf_msg_fragments = -1;
static int hf_msg_fragment = -1;
static int hf_msg_fragment_overlap = -1;
@ -968,8 +869,7 @@ static gint *ett[] =
...
&ett_msg_fragment,
&ett_msg_fragments
...
]]>
...]]>
</programlisting></example>
<para>
These hf variables are used internally within the reassembly routines
@ -1007,12 +907,10 @@ static gint *ett[] =
<example>
<title>Reassembling TCP fragments</title>
<programlisting>
<![CDATA[
#ifdef HAVE_CONFIG_H
<![CDATA[#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gmodule.h>
#include <epan/packet.h>
#include <epan/emem.h>
#include <epan/dissectors/packet-tcp.h>
@ -1042,8 +940,7 @@ static guint get_foo_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
return (guint)tvb_get_ntohl(tvb, offset+4); /* e.g. length is at offset 4 */
}
...
]]>
...]]>
</programlisting>
</example>
<para>
@ -1084,8 +981,7 @@ static guint get_foo_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
</para>
<example><title>Initialising a tap</title>
<programlisting>
<![CDATA[
#include <epan/tap.h>
<![CDATA[#include <epan/tap.h>
static int foo_tap = -1;
@ -1095,8 +991,7 @@ struct FooTap {
...
};
...
foo_tap = register_tap("foo");
]]>
foo_tap = register_tap("foo");]]>
</programlisting></example>
<para>
Whilst you can program a tap without protocol specific data, it
@ -1117,7 +1012,7 @@ struct FooTap {
</para>
<example><title>Calling a protocol tap</title>
<programlisting>
<![CDATA[
<![CDATA[
static struct FooTap pinfo;
pinfo.packet_type = tvb_get_guint8(tvb, 0);
@ -1149,8 +1044,7 @@ struct FooTap {
</para>
<example><title>Initialising a stats interface</title>
<programlisting>
<![CDATA[
/* register all http trees */
<![CDATA[/* register all http trees */
static void register_foo_stat_trees(void) {
stats_tree_register("foo","foo","Foo/Packet Types",
foo_stats_tree_packet, foo_stats_tree_init, NULL );
@ -1163,8 +1057,7 @@ G_MODULE_EXPORT void plugin_register_tap_listener(void)
register_foo_stat_trees();
}
#endif
]]>
#endif]]>
</programlisting></example>
<para>
Working from the bottom up, first the plugin interface entry point is defined,
@ -1200,8 +1093,7 @@ G_MODULE_EXPORT void plugin_register_tap_listener(void)
</para>
<example><title>Initialising a stats session</title>
<programlisting>
<![CDATA[
static const guint8* st_str_packets = "Total Packets";
<![CDATA[static const guint8* st_str_packets = "Total Packets";
static const guint8* st_str_packet_types = "FOO Packet Types";
static int st_node_packets = -1;
static int st_node_packet_types = -1;
@ -1209,8 +1101,7 @@ static int st_node_packet_types = -1;
static void foo_stats_tree_init(stats_tree* st) {
st_node_packets = stats_tree_create_node(st, st_str_packets, 0, TRUE);
st_node_packet_types = stats_tree_create_pivot(st, st_str_packet_types, st_node_packets);
}
]]>
}]]>
</programlisting></example>
<para>
In this case we create a new tree node, to handle the total packets,
@ -1219,16 +1110,14 @@ static void foo_stats_tree_init(stats_tree* st) {
</para>
<example><title>Generating the stats</title>
<programlisting>
<![CDATA[
static int foo_stats_tree_packet(stats_tree* st, packet_info* pinfo,
<![CDATA[static int foo_stats_tree_packet(stats_tree* st, packet_info* pinfo,
epan_dissect_t* edt, const void* p) {
struct FooTap *pi = (struct FooTap *)p;
tick_stat_node(st, st_str_packets, 0, FALSE);
stats_tree_tick_pivot(st, st_node_packet_types,
val_to_str(pi->packet_type, msgtypevalues, "Unknown packet type (%d)"));
return 1;
}
]]>
}]]>
</programlisting></example>
<para>
In this case the processing of the stats is quite simple.
@ -1243,7 +1132,7 @@ epan_dissect_t* edt, const void* p) {
<title>How to use conversations</title>
<para>
Some info about how to use conversations in a dissector can be
found in the file doc/README.developer.
found in the file doc/README.developer chapter 2.2.
</para>
</section>

View File

@ -7,7 +7,7 @@
developer machine.</para>
<para>If a tool is not already installed on your system, you
will typically use the installation package from your
distribution (by your favourite package manager: apt, yum,
distribution (by your favourite package manager: aptitude, yum,
synaptics, ...).</para>
<para>If an install package is not available, or you have a
reason not to use it (maybe because it's simply too old), you

View File

@ -1343,9 +1343,12 @@ Copyright (C) 2000-2006 CollabNet.
least the major/minor versions (e.g. 1.4).</para>
</warning>
<section id="ChToolsUnixSVNGUI">
<title>UNIX or Win32 Cygwin: -</title>
<para>XXX - could someone recommend a good UNIX GUI client
for subversion?</para>
<title>UNIX or Win32 Cygwin: rapidSVN, subcommander</title>
<para>RapidSVN is a cross platform subversion frontend based on wxWidgets.
It can be found at: <ulink url="http://rapidsvn.tigris.org/" />.
Subcommander is another cross platform subversion frontend. It can
be found at: <ulink url="http://subcommander.tigris.org/" />.
</para>
<para>Cygwin don't provide any GUI client for
subversion.</para>
</section>
@ -1513,7 +1516,7 @@ written by Larry Wall and Paul Eggert]]>
files needed to be installed, including all required DLL's and
such.</para>
<para>To install it, simply download the latest released
version (currently: 2.22) from
version (currently: 2.28) from
<ulink url="http://nsis.sourceforge.net" />and start the
downloaded installer. You will need NSIS version 2 final or
higher.</para>