2004-07-18 00:24:25 +00:00
|
|
|
$Id$
|
2002-11-28 20:29:46 +00:00
|
|
|
|
2009-02-05 15:25:48 +00:00
|
|
|
The TAP system in Wireshark is a powerful and flexible mechanism to get event
|
2002-09-06 14:04:25 +00:00
|
|
|
driven notification on packets matching certain protocols and/or filters.
|
2007-02-13 02:06:04 +00:00
|
|
|
In order to use the tapping system, very little knowledge of Wireshark
|
2002-09-06 14:04:25 +00:00
|
|
|
internals are required.
|
|
|
|
|
2009-02-05 15:25:48 +00:00
|
|
|
As examples on how to use the tap system see the implementation of
|
2006-05-31 17:38:42 +00:00
|
|
|
tap-rpcstat.c (tshark version)
|
2007-02-13 02:06:04 +00:00
|
|
|
gtk/rpc_stat.c (gtk-wireshark version)
|
2002-09-06 14:04:25 +00:00
|
|
|
|
2005-04-01 08:47:42 +00:00
|
|
|
If all you need is to keep some counters, there's the stats_tree API,
|
2006-05-31 17:38:42 +00:00
|
|
|
which offers a simple way to make a GUI and tshark tap-listener; see
|
2005-04-01 08:47:42 +00:00
|
|
|
README.stats_tree. However, keep reading, as you'll need much of what's
|
|
|
|
in this document.
|
2002-09-06 14:04:25 +00:00
|
|
|
|
|
|
|
The tap system consists of two parts:
|
|
|
|
1, code in the actual dissectors to allow tapping data from that particular
|
|
|
|
protocol dissector, and
|
|
|
|
2, event driven code in an extension such as tap-rpcstat.c that registers
|
|
|
|
a tap listener and processes received data.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
So you want to hack together a tap application?
|
|
|
|
|
|
|
|
|
|
|
|
TAP
|
|
|
|
===
|
|
|
|
First you must decide which protocol you are interested in writing a tap
|
2002-11-28 20:29:46 +00:00
|
|
|
application for and check if that protocol has already got a tap installed
|
2002-09-06 14:04:25 +00:00
|
|
|
in it.
|
2007-02-13 02:06:04 +00:00
|
|
|
If it already has a tap device installed then you don't have to do anything.
|
2009-02-05 15:25:48 +00:00
|
|
|
If not, then you have to add a tap but don't worry, this is extremely easy to
|
2002-09-06 14:04:25 +00:00
|
|
|
do and is done in four easy steps;
|
|
|
|
(see packet-rpc.c and search for tap for an example)
|
|
|
|
|
|
|
|
1, We need tap.h so just add '#include "tap.h"' to the includes.
|
|
|
|
|
|
|
|
2, We need a tap handler so just add 'static int <protocol>_tap = -1;'
|
|
|
|
|
|
|
|
3, Down in proto_register_<protocol>() you need to add
|
|
|
|
'<protocol>_tap = register_tap("<protocol>");'
|
|
|
|
|
|
|
|
4, In the actual dissector for that protocol, after any child dissectors
|
|
|
|
have returned, just add 'tap_queue_packet(<protocol>_tap, pinfo, <pointer>);'
|
|
|
|
|
2007-10-12 19:13:31 +00:00
|
|
|
<pointer> is used if the tap has any special additional data to provide to the
|
|
|
|
tap listeners. What this points to is dependent on the protocol that is tapped,
|
|
|
|
or if there are no useful extra data to provide just specify NULL. For
|
|
|
|
packet-rpc.c what we specify there is the persistent structure 'rpc_call' which
|
|
|
|
contains lots of useful information from the rpc layer that a listener might
|
2002-09-06 14:04:25 +00:00
|
|
|
need.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TAP LISTENER
|
|
|
|
============
|
|
|
|
(see tap-rpcstat.c as an example)
|
2009-02-05 15:25:48 +00:00
|
|
|
Interfacing your application is not that much harder either.
|
2002-09-06 14:04:25 +00:00
|
|
|
Only 3 callbacks and two functions.
|
|
|
|
|
|
|
|
|
|
|
|
The two functions to start or stop tapping are
|
|
|
|
|
2009-06-05 22:42:47 +00:00
|
|
|
register_tap_listener(const char *tapname, void *tapdata, const char *fstring,
|
|
|
|
guint flags,
|
|
|
|
void (*reset)(void *tapdata),
|
|
|
|
gboolean (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *<pointer>),
|
2003-11-29 12:34:33 +00:00
|
|
|
void (*draw)(void *tapdata));
|
2002-09-06 14:04:25 +00:00
|
|
|
|
|
|
|
remove_tap_listener(void *tapdata);
|
|
|
|
|
|
|
|
|
|
|
|
remove_tap_listener(void *tapdata)
|
|
|
|
This function is used to deregister and stop a tap listener.
|
|
|
|
|
2002-11-28 20:29:46 +00:00
|
|
|
register_tap_listener() is used to register an instance of a tap application
|
2002-09-06 14:04:25 +00:00
|
|
|
to the tap system.
|
|
|
|
|
2009-02-05 15:25:48 +00:00
|
|
|
*tapname
|
2002-09-06 14:04:25 +00:00
|
|
|
is the name of the tap we want to listen to. I.e. the name used in
|
|
|
|
step 3 above.
|
|
|
|
|
2009-02-05 15:25:48 +00:00
|
|
|
*tapdata
|
2002-09-06 14:04:25 +00:00
|
|
|
is the instance identifier. The tap system uses the value of this
|
|
|
|
pointer to distinguish between different instances of a tap.
|
|
|
|
Just make sure that it is unique by letting it be the pointer to a struct
|
|
|
|
holding all state variables. If you want to allow multiple concurrent
|
|
|
|
instances, just put ALL state variables inside a struct allocated by
|
|
|
|
g_malloc() and use that pointer.
|
|
|
|
(tap-rpcstat.c use this technique to allow multiple simultaneous instances)
|
|
|
|
|
2009-02-05 15:25:48 +00:00
|
|
|
*fstring
|
|
|
|
is a pointer to a filter string.
|
2002-09-06 14:04:25 +00:00
|
|
|
If this is NULL, then the tap system will provide ALL packets passing the
|
|
|
|
tapped protocol to your listener.
|
|
|
|
If you specify a filter string here the tap system will first try
|
|
|
|
to apply this string to the packet and then only pass those packets that
|
|
|
|
matched the filter to your listener.
|
|
|
|
The syntax for the filter string is identical to normal display filters.
|
|
|
|
|
|
|
|
NOTE: Specifying filter strings will have a significant performance impact
|
2007-02-13 02:06:04 +00:00
|
|
|
on your application and Wireshark. If possible it is MUCH better to take
|
2002-09-06 14:04:25 +00:00
|
|
|
unfiltered data and just filter it yourself in the packet-callback than
|
|
|
|
to specify a filter string.
|
|
|
|
ONLY use a filter string if no other option exist.
|
|
|
|
|
2009-06-05 22:42:47 +00:00
|
|
|
flags
|
|
|
|
is a set of flags for the tap listener. The flags that can be set are:
|
|
|
|
|
|
|
|
TL_REQUIRES_PROTO_TREE
|
|
|
|
|
|
|
|
set if your tap listener "packet" routine requires a protocol
|
|
|
|
tree to be built. It will require a protocol tree to be
|
|
|
|
built if either
|
|
|
|
|
|
|
|
1) it looks at the protocol tree in edt->tree
|
|
|
|
|
|
|
|
or
|
|
|
|
|
|
|
|
2) the tap-specific data passed to it is constructed only if
|
|
|
|
the protocol tree is being built.
|
|
|
|
|
|
|
|
TL_REQUIRES_COLUMNS
|
|
|
|
|
|
|
|
set if your tap listener "packet" routine requires the column
|
|
|
|
strings to be constructed.
|
|
|
|
|
2002-09-06 14:04:25 +00:00
|
|
|
void (*reset)(void *tapdata)
|
2007-02-13 02:06:04 +00:00
|
|
|
This callback is called whenever Wireshark wants to inform your
|
2002-09-06 14:04:25 +00:00
|
|
|
listener that it is about to start [re]reading a capture file or a new capture
|
|
|
|
from an interface and that your application should reset any state it has
|
|
|
|
in the *tapdata instance.
|
|
|
|
|
2009-06-05 22:42:47 +00:00
|
|
|
gboolean (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, void *data)
|
2002-09-06 14:04:25 +00:00
|
|
|
This callback is used whenever a new packet has arrived at the tap and that
|
|
|
|
it has passed the filter (if there were a filter).
|
|
|
|
The *data structure type is specific to each tap.
|
2009-06-05 22:42:47 +00:00
|
|
|
This function returns an gboolean and it should return
|
|
|
|
TRUE, if the data in the packet caused state to be updated
|
|
|
|
(and thus a redraw of the window would later be required)
|
|
|
|
FALSE, if we don't need to redraw the window.
|
2002-09-06 14:04:25 +00:00
|
|
|
NOTE: that (*packet) should be as fast and efficient as possible. Use this
|
2007-02-13 02:06:04 +00:00
|
|
|
function ONLY to store data for later and do the CPU-intensive processing
|
2002-09-06 14:04:25 +00:00
|
|
|
or GUI updates down in (*draw) instead.
|
|
|
|
|
2009-02-05 15:25:48 +00:00
|
|
|
|
2002-09-06 14:04:25 +00:00
|
|
|
void (*draw)(void *tapdata)
|
2007-02-13 02:06:04 +00:00
|
|
|
This callback is used when Wireshark wants your application to redraw its
|
2002-09-06 14:04:25 +00:00
|
|
|
output. It will usually not be called unless your application has received
|
|
|
|
new data through the (*packet) callback.
|
2009-02-05 15:25:48 +00:00
|
|
|
On some ports of Wireshark (gtk2) (*draw) will be called asynchronously
|
2002-09-06 14:04:25 +00:00
|
|
|
from a separate thread up to once every 2-3 seconds.
|
|
|
|
On other ports it might only be called once when the capture is finished
|
|
|
|
or the file has been [re]read completely.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
So, create three callbacks:
|
|
|
|
1, reset to reset the state variables in the structure passed to it.
|
|
|
|
2, packet to update these state variables.
|
|
|
|
3, draw to take these state variables and draw them on the screen.
|
|
|
|
|
2007-02-13 02:06:04 +00:00
|
|
|
then just make Wireshark call register_tap_listener() when you want to tap
|
2002-09-06 14:04:25 +00:00
|
|
|
and call remove_tap_listener() when you are finished.
|
|
|
|
|
|
|
|
|
2005-06-09 05:40:26 +00:00
|
|
|
WHEN DO TAP LISTENERS GET CALLED?
|
2003-03-06 07:54:24 +00:00
|
|
|
===================================
|
2007-02-13 02:06:04 +00:00
|
|
|
Tap listeners are only called when Wireshark reads a new capture for
|
|
|
|
the first time or whenever Wireshark needs to rescan/redissect
|
2003-03-06 07:54:24 +00:00
|
|
|
the capture.
|
|
|
|
Redissection occurs when you apply a new display filter or if you
|
|
|
|
change and Save/Apply a preference setting that might affect how
|
|
|
|
packets are dissected.
|
|
|
|
After each individual packet has been completely dissected and all
|
2007-10-12 19:13:31 +00:00
|
|
|
dissectors have returned, all the tap listeners that have been flagged
|
2003-03-06 07:54:24 +00:00
|
|
|
to receive tap data during the dissection of the frame will be called in
|
|
|
|
sequence.
|
2007-10-12 19:13:31 +00:00
|
|
|
The order in which the tap listeners will be called is not defined.
|
2003-03-06 07:54:24 +00:00
|
|
|
Not until all tap listeners for the frame has been called and returned
|
2007-02-13 02:06:04 +00:00
|
|
|
will Wireshark continue to dissect the next packet.
|
2003-03-06 07:54:24 +00:00
|
|
|
This is why it is important to make the *_packet() callbacks execute as
|
|
|
|
quickly as possible, else we create an extra delay until the next packet
|
|
|
|
is dissected.
|
|
|
|
|
|
|
|
Keep in mind though: for some protocols, such as IP, the protocol can
|
|
|
|
appear multiple times in different layers inside the same packet.
|
|
|
|
For example, IP encapsulated over IP which will call the ip dissector
|
|
|
|
twice for the same packet.
|
2009-02-05 15:25:48 +00:00
|
|
|
IF the tap is going to return private data using the last parameter to
|
|
|
|
tap_queue_packet() and IF the protocol can appear multiple times inside the
|
|
|
|
same packet, you will have to make sure that each instance of
|
2003-03-06 07:54:24 +00:00
|
|
|
tap_queue_packet() is using its own instance of private struct variable
|
2007-02-13 02:06:04 +00:00
|
|
|
so they don't overwrite each other.
|
2003-03-06 07:54:24 +00:00
|
|
|
|
2009-05-20 15:50:40 +00:00
|
|
|
See packet-ip.c which has a simple solution to the problem. It creates
|
|
|
|
a unique instance of the IP header using ep_alloc().
|
|
|
|
Previous versions used a static struct of 4 instances of the IP header
|
|
|
|
struct and cycled through them each time the dissector was called. (4
|
|
|
|
was just a number taken out of the blue but it should be enough for most
|
|
|
|
cases.) This would fail if there were more than 4 IP headers in the same
|
|
|
|
packet, but that was unlikely.
|
2002-09-06 14:04:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
TIPS
|
|
|
|
====
|
|
|
|
Of course, there is nothing that forces you to make (*draw) draw stuff
|
2009-02-05 15:25:48 +00:00
|
|
|
on the screen.
|
2002-09-06 14:04:25 +00:00
|
|
|
You can hand register_tap_listener() NULL for both (*draw) and (*reset)
|
|
|
|
(well also for (*packet) but that would be a very boring extension).
|
|
|
|
|
|
|
|
Perhaps you want an extension that will execute a certain command
|
2007-02-13 02:06:04 +00:00
|
|
|
every time it sees a certain packet?
|
2002-09-06 14:04:25 +00:00
|
|
|
Well, try this :
|
|
|
|
int packet(void *tapdata,...) {
|
|
|
|
...
|
|
|
|
system("mail ...");
|
|
|
|
return0;
|
|
|
|
}
|
|
|
|
|
|
|
|
register_tap_listener("tcp", struct, "tcp.port==57", NULL, packet, NULL);
|
|
|
|
|
|
|
|
Let struct contain an email address?
|
2007-02-13 02:06:04 +00:00
|
|
|
Then you have something simple that will make Wireshark send an email
|
2009-02-05 15:25:48 +00:00
|
|
|
out automagically for each and every time it dissects
|
2002-10-25 01:11:03 +00:00
|
|
|
a packet containing TCP traffic to port 57.
|
2002-09-06 14:04:25 +00:00
|
|
|
Please put in some rate limitation if you do this.
|
|
|
|
|
|
|
|
Let struct contain a command line and make (*packet) execute it?
|
|
|
|
The possibilities are rather large.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
See tap-rpcstat.c for an example
|
2009-02-05 15:25:48 +00:00
|
|
|
See tap.c as well. It contains lots of comments and descriptions on the tap
|
2002-09-06 14:05:59 +00:00
|
|
|
system.
|
2002-09-06 14:04:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|