aboutsummaryrefslogtreecommitdiffstats
path: root/doc/README.tapping
blob: 328bbade3fa47c2b81629f48f807c3487c6ee4eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
$Id$

The TAP system in ethereal 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 ethereal
internals are required.

As examples on how to use the tap system see the implementation of 
tap-rpcstat.c     	(tethereal version)
gtk/gtk-rpcstat.c	(gtk-ethereal 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 tethereal 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 dont have to do anything.
If not, then you have to add a tap but dont 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 "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>);'

<pointer> is used if the tap has any special additional data to provide to
the tap listeners. What this points to is dependant 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 the rpc layer that a listener might
need.



TAP LISTENER
============
(see tap-rpcstat.c as an example)
Interfacing your application is not that much harder either.
Only 3 callbacks and two functions.


The two functions to start or stop tapping are

register_tap_listener(char *tapname, void *tapdata, char *fstring,
	void (*reset)(void *tapdata),
	int  (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *<pointer>),
	void (*draw)(void *tapdata));

remove_tap_listener(void *tapdata);


remove_tap_listener(void *tapdata)
This function is used to deregister and stop a tap listener.

register_tap_listener() is used to register an instance of a tap application
to the tap system.

*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_malloc() 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 ethereal. 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.

void (*reset)(void *tapdata)
This callback is called whenever ethereal 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.

int (*packet)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, void *data)
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.
This function returns an int and it should return 
 1, if the data in the packet aused state to be updated
    (asnd thus a redraw of the window would later be required)
 0, if we dont need to redraw the window.
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 ethereal 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 ethereal (gtk2) (*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.



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.

then just make ethereal 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 ethereal reads a new capture for
the first time or whenever ethereal 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 has been flagged
to receive tap data during the dissection of the frame will be called in
sequence.
The order of which the tap listeners will be called is not defined.
Not until all tap listeners for the frame has been called and returned
will ethereal 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 dont overwrite eachother.

See packet-ip.c which has a simple solution to the problem. It just
uses a static struct of 4 instances of the ip header struct and
cycles through them each time the dissector is called.
4 is just a number taken out of the blue but it should be enough for most
cases.
Of course, if someone would generate a capture with IP encapsulated
over IP over IP over IP over IP, so that there would be more than 4 IP headers
in the same packet, yes then this would fail.   The likelyhood of this 
happening in real life is probably very low. If it turns out to be a problem
we can just increase the cycle length when that happens.


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 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
everytime it sees a certain packet?
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?
	Then you have something simple that will make ethereal 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-rpcstat.c for an example
See tap.c as well. It contains lots of comments and descriptions on the tap 
system.