summaryrefslogtreecommitdiffstats
path: root/doc/README.tapping
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /doc/README.tapping
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/README.tapping')
-rw-r--r--doc/README.tapping244
1 files changed, 244 insertions, 0 deletions
diff --git a/doc/README.tapping b/doc/README.tapping
new file mode 100644
index 00000000..4fcb6389
--- /dev/null
+++ b/doc/README.tapping
@@ -0,0 +1,244 @@
+The TAP system in Wireshark is a powerful and flexible mechanism to get event
+driven notification on packets matching certain protocols and/or filters.
+In order to use the tapping system, very little knowledge of Wireshark
+internals is required.
+
+As examples on how to use the tap system see the implementation of
+tap-rpcprogs.c (tshark version)
+ui/qt/rpc_service_response_time_dialog.cpp (wireshark version)
+
+If all you need is to keep some counters, there's the stats_tree API,
+which offers a simple way to make a GUI and tshark tap-listener; see
+README.stats_tree. However, keep reading, as you'll need much of what's
+in this document.
+
+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
+application for and check if that protocol has already got a tap installed
+in it.
+If it already has a tap device installed then you don't have to do anything.
+If not, then you have to add a tap but don't worry, this is extremely easy to
+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 <epan/tap.h>' (preceded by packet.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>);'
+
+<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 is 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
+need.
+
+
+
+TAP LISTENER
+============
+(see tap-rpcprogs.c as an example)
+Interfacing your application is not that much harder either.
+Only 4 callbacks and two functions.
+
+The two functions to start or stop tapping are
+
+register_tap_listener(const char *tapname, void *tapdata, const char *fstring,
+ unsigned flags,
+ void (*reset)(void *tapdata),
+ tap_packet_status (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data),
+ void (*draw)(void *tapdata),
+ void (*finish)(void *tapdata));
+
+This function is used to register an instance of a tap application
+to the tap system.
+
+remove_tap_listener(void *tapdata);
+
+This function is used to deregister and stop a tap listener.
+
+The parameters have the following meanings:
+
+*tapname
+is the name of the tap we want to listen to. I.e. the name used in
+step 3 above.
+
+*tapdata
+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_new() and use that pointer.
+(tap-rpcstat.c use this technique to allow multiple simultaneous instances)
+
+*fstring
+is a pointer to a filter string.
+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
+on your application and Wireshark. If possible it is MUCH better to take
+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.
+
+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.
+
+ TL_REQUIRES_ERROR_PACKET
+
+ set if your tap listener should be updated even when pinfo->flags.in_error_pkt is set
+ e.g. if it is inside an ICMP unreachable packet
+
+ If no flags are needed, use TL_REQUIRES_NOTHING.
+
+void (*reset)(void *tapdata)
+This callback is called whenever Wireshark wants to inform your
+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.
+
+tap_packet_status (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data)
+This callback is used whenever a new packet has arrived at the tap and that
+it has passed the filter (if there was a filter).
+The *data structure type is specific to each tap.
+This function returns a tap_packet_status enum and it should return
+ TAP_PACKET_REDRAW, if the data in the packet caused state to be updated
+ (and thus a redraw of the window would later be required)
+ TAP_PACKET_DONT_REDRAW, if we don't need to redraw the window
+ TAP_PACKET_FAILED, if the tap failed and shouldn't be called again
+ in this pass (for example, if it's writing to a file and gets
+ an I/O error)
+NOTE: that (*packet) should be as fast and efficient as possible. Use this
+function ONLY to store data for later and do the CPU-intensive processing
+or GUI updates down in (*draw) instead.
+
+
+void (*draw)(void *tapdata)
+This callback is used when Wireshark wants your application to redraw its
+output. It will usually not be called unless your application has received
+new data through the (*packet) callback.
+On some ports of Wireshark (Qt) (*draw) will be called asynchronously
+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.
+
+void (*finish)(void *tapdata)
+This callback is called when your listener is removed.
+
+
+So, create four 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.
+4, finish to free all state variables.
+
+then just make Wireshark call register_tap_listener() when you want to tap
+and call remove_tap_listener() when you are finished.
+
+
+WHEN DO TAP LISTENERS GET CALLED?
+===================================
+Tap listeners are only called when Wireshark reads a new capture for
+the first time or whenever Wireshark needs to rescan/redissect
+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
+dissectors have returned, all the tap listeners that have been flagged
+to receive tap data during the dissection of the frame will be called in
+sequence.
+The order in which the tap listeners will be called is not defined.
+Not until all tap listeners for the frame has been called and returned
+will Wireshark continue to dissect the next packet.
+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.
+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
+tap_queue_packet() is using its own instance of private struct variable
+so they don't overwrite each other.
+
+See packet-ip.c which has a simple solution to the problem. It creates
+a unique instance of the IP header using wmem_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.
+
+
+TIPS
+====
+Of course, there is nothing that forces you to make (*draw) draw stuff
+on the screen.
+You can hand register_tap_listener() NULL for (*draw), (*reset) and (*finish)
+(well also for (*packet) but that would be a very boring extension).
+
+Perhaps you want an extension that will execute a certain command
+every time it sees a certain packet?
+Well, try this :
+ tap_packet_status packet(void *tapdata,...) {
+ ...
+ system("mail ...");
+ return TAP_PACKET_DONT_REDRAW;
+ }
+
+ register_tap_listener("tcp", struct, "tcp.port==57", NULL, packet, NULL, NULL);
+
+ Let struct contain an email address?
+ Then you have something simple that will make Wireshark send an email
+ out automagically for each and every time it dissects
+ a packet containing TCP traffic to port 57.
+ 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.c as well. It contains lots of comments and descriptions on the tap
+system.