2 * packet tap interface 2002 Ronnie Sahlberg
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
33 #ifdef HAVE_NETINET_IN_H
34 # include <netinet/in.h>
38 #include <epan/packet_info.h>
39 #include <epan/dfilter/dfilter.h>
42 static gboolean tapping_is_active
=FALSE
;
44 typedef struct _tap_dissector_t
{
45 struct _tap_dissector_t
*next
;
48 static tap_dissector_t
*tap_dissector_list
=NULL
;
51 * This is the list of free and used packets queued for a tap.
52 * It is implemented here explicitly instead of using GLib objects
53 * in order to be as fast as possible as we need to build and tear down the
54 * queued list at least once for each packet we see and thus we must be able
55 * to build and tear it down as fast as possible.
57 typedef struct _tap_packet_t
{
60 const void *tap_specific_data
;
63 #define TAP_PACKET_QUEUE_LEN 100
64 static tap_packet_t tap_packet_array
[TAP_PACKET_QUEUE_LEN
];
65 static guint tap_packet_index
;
67 typedef struct _tap_listener_t
{
68 struct _tap_listener_t
*next
;
70 gboolean needs_redraw
;
78 static volatile tap_listener_t
*tap_listener_queue
=NULL
;
80 /* **********************************************************************
81 * Init routine only called from epan at application startup
82 * ********************************************************************** */
83 /* This function is called once when wireshark starts up and is used
84 to init any data structures we may need later.
94 /* **********************************************************************
95 * Functions called from dissector when made tappable
96 * ********************************************************************** */
97 /* the following two functions are used from dissectors to
98 1. register the ability to tap packets from this subdissector
99 2. push packets encountered by the subdissector to anyone tapping
102 /* This function registers that a dissector has the packet tap ability
103 available. The name parameter is the name of this tap and extensions can
104 use open_tap(char *name,... to specify that it wants to receive packets/
105 events from this tap.
107 This function is only to be called once, when the dissector initializes.
109 The return value from this call is later used as a parameter to the
110 tap_packet(unsigned int *tap_id,...
111 call so that the tap subsystem knows to which tap point this tapped
112 packet is associated.
115 register_tap(const char *name
)
117 tap_dissector_t
*td
, *tdl
;
120 if(tap_dissector_list
){
121 tap_id
=find_tap_id(name
);
126 td
=(tap_dissector_t
*)g_malloc(sizeof(tap_dissector_t
));
128 td
->name
= g_strdup(name
);
130 if(!tap_dissector_list
){
131 tap_dissector_list
=td
;
134 for(i
=2,tdl
=tap_dissector_list
;tdl
->next
;i
++,tdl
=tdl
->next
)
142 /* Everytime the dissector has finished dissecting a packet (and all
143 subdissectors have returned) and if the dissector has been made "tappable"
144 it will push some data to everyone tapping this layer by a call
145 to tap_queue_packet().
146 The first parameter is the tap_id returned by the register_tap()
147 call for this dissector (so the tap system can keep track of who it came
148 from and who is listening to it)
149 The second is the packet_info structure which many tap readers will find
151 The third argument is specific to each tap point or NULL if no additional
152 data is available to this tap. A tap point in say IP will probably want to
153 push the IP header structure here. Same thing for TCP and ONCRPC.
155 The pinfo and the specific pointer are what is supplied to every listener
156 in the read_callback() call made to every one currently listening to this
159 The tap reader is responsible to know how to parse any structure pointed
160 to by the tap specific data pointer.
163 tap_queue_packet(int tap_id
, packet_info
*pinfo
, const void *tap_specific_data
)
167 if(!tapping_is_active
){
171 * XXX - should we allocate this with an ep_allocator,
172 * rather than having a fixed maximum number of entries?
174 if(tap_packet_index
>= TAP_PACKET_QUEUE_LEN
){
175 g_warning("Too many taps queued");
179 tpt
=&tap_packet_array
[tap_packet_index
];
182 tpt
->tap_specific_data
=tap_specific_data
;
190 /* **********************************************************************
191 * Functions used by file.c to drive the tap subsystem
192 * ********************************************************************** */
194 void tap_build_interesting (epan_dissect_t
*edt
)
198 /* nothing to do, just return */
199 if(!tap_listener_queue
){
203 /* loop over all tap listeners and build the list of all
204 interesting hf_fields */
205 for(tl
=(tap_listener_t
*)tap_listener_queue
;tl
;tl
=tl
->next
){
207 epan_dissect_prime_dfilter(edt
, tl
->code
);
212 /* This function is used to delete/initialize the tap queue and prime an
213 epan_dissect_t with all the filters for tap listeners.
214 To free the tap queue, we just prepend the used queue to the free queue.
217 tap_queue_init(epan_dissect_t
*edt
)
219 /* nothing to do, just return */
220 if(!tap_listener_queue
){
224 tapping_is_active
=TRUE
;
228 tap_build_interesting (edt
);
231 /* this function is called after a packet has been fully dissected to push the tapped
232 data to all extensions that has callbacks registered.
235 tap_push_tapped_queue(epan_dissect_t
*edt
)
241 /* nothing to do, just return */
242 if(!tapping_is_active
){
246 tapping_is_active
=FALSE
;
248 /* nothing to do, just return */
249 if(!tap_packet_index
){
253 /* loop over all tap listeners and call the listener callback
254 for all packets that match the filter. */
255 for(i
=0;i
<tap_packet_index
;i
++){
256 for(tl
=(tap_listener_t
*)tap_listener_queue
;tl
;tl
=tl
->next
){
257 tp
=&tap_packet_array
[i
];
258 if(tp
->tap_id
==tl
->tap_id
){
259 gboolean passed
=TRUE
;
261 passed
=dfilter_apply_edt(tl
->code
, edt
);
263 if(passed
&& tl
->packet
){
264 tl
->needs_redraw
|=tl
->packet(tl
->tapdata
, tp
->pinfo
, edt
, tp
->tap_specific_data
);
272 /* This function can be used by a dissector to fetch any tapped data before
274 * This can be useful if one wants to extract the data inside dissector BEFORE
275 * it exists as an alternative to the callbacks that are all called AFTER the
276 * dissection has completed.
278 * Example: SMB2 uses this mechanism to extract the data tapped from NTLMSSP
279 * containing the account and domain names before exiting.
280 * Note that the SMB2 tap listener specifies all three callbacks as NULL.
282 * Beware: when using this mechanism to extract the tapped data you can not
283 * use "filters" and should specify the "filter" as NULL when registering
287 fetch_tapped_data(int tap_id
, int idx
)
292 /* nothing to do, just return */
293 if(!tapping_is_active
){
297 /* nothing to do, just return */
298 if(!tap_packet_index
){
302 /* loop over all tapped packets and return the one with index idx */
303 for(i
=0;i
<tap_packet_index
;i
++){
304 tp
=&tap_packet_array
[i
];
305 if(tp
->tap_id
==tap_id
){
307 return tp
->tap_specific_data
;
315 /* This function is called when we need to reset all tap listeners, for example
316 when we open/start a new capture or if we need to rescan the packet list.
319 reset_tap_listeners(void)
323 for(tl
=(tap_listener_t
*)tap_listener_queue
;tl
;tl
=tl
->next
){
325 tl
->reset(tl
->tapdata
);
327 tl
->needs_redraw
=TRUE
;
333 /* This function is called when we need to redraw all tap listeners, for example
334 when we open/start a new capture or if we need to rescan the packet list.
335 It should be called from a low priority thread say once every 3 seconds
337 If draw_all is true, redraw all aplications regardless if they have
341 draw_tap_listeners(gboolean draw_all
)
345 for(tl
=(tap_listener_t
*)tap_listener_queue
;tl
;tl
=tl
->next
){
346 if(tl
->needs_redraw
|| draw_all
){
348 tl
->draw(tl
->tapdata
);
351 tl
->needs_redraw
=FALSE
;
357 /* **********************************************************************
358 * Functions used by tap to
359 * 1. register that a really simple extension is available for use by
361 * 2. start tapping from a subdissector
362 * 3. close an already open tap
363 * ********************************************************************** */
364 /* this function will return the tap_id for the specific protocol tap
365 or 0 if no such tap was found.
368 find_tap_id(const char *name
)
373 for(i
=1,td
=tap_dissector_list
;td
;i
++,td
=td
->next
) {
374 if(!strcmp(td
->name
,name
)){
381 /* this function attaches the tap_listener to the named tap.
384 * non-NULL: error, return value points to GString containing error
388 register_tap_listener(const char *tapname
, void *tapdata
, const char *fstring
,
389 guint flags
, tap_reset_cb reset
, tap_packet_cb packet
, tap_draw_cb draw
)
393 GString
*error_string
;
395 tap_id
=find_tap_id(tapname
);
397 error_string
= g_string_new("");
398 g_string_printf(error_string
, "Tap %s not found", tapname
);
402 tl
=(tap_listener_t
*)g_malloc(sizeof(tap_listener_t
));
404 tl
->needs_redraw
=TRUE
;
407 if(!dfilter_compile(fstring
, &tl
->code
)){
408 error_string
= g_string_new("");
409 g_string_printf(error_string
,
410 "Filter \"%s\" is invalid - %s",
411 fstring
, dfilter_error_msg
);
422 tl
->next
=(tap_listener_t
*)tap_listener_queue
;
424 tap_listener_queue
=tl
;
429 /* this function sets a new dfilter to a tap listener
432 set_tap_dfilter(void *tapdata
, const char *fstring
)
434 tap_listener_t
*tl
=NULL
,*tl2
;
435 GString
*error_string
;
437 if(!tap_listener_queue
){
441 if(tap_listener_queue
->tapdata
==tapdata
){
442 tl
=(tap_listener_t
*)tap_listener_queue
;
444 for(tl2
=(tap_listener_t
*)tap_listener_queue
;tl2
->next
;tl2
=tl2
->next
){
445 if(tl2
->next
->tapdata
==tapdata
){
455 dfilter_free(tl
->code
);
458 tl
->needs_redraw
=TRUE
;
460 if(!dfilter_compile(fstring
, &tl
->code
)){
461 error_string
= g_string_new("");
462 g_string_printf(error_string
,
463 "Filter \"%s\" is invalid - %s",
464 fstring
, dfilter_error_msg
);
473 /* this function removes a tap listener
476 remove_tap_listener(void *tapdata
)
478 tap_listener_t
*tl
=NULL
,*tl2
;
480 if(!tap_listener_queue
){
484 if(tap_listener_queue
->tapdata
==tapdata
){
485 tl
=(tap_listener_t
*)tap_listener_queue
;
486 tap_listener_queue
=tap_listener_queue
->next
;
488 for(tl2
=(tap_listener_t
*)tap_listener_queue
;tl2
->next
;tl2
=tl2
->next
){
489 if(tl2
->next
->tapdata
==tapdata
){
491 tl2
->next
=tl2
->next
->next
;
500 dfilter_free(tl
->code
);
509 * Return TRUE if we have one or more tap listeners that require dissection,
513 tap_listeners_require_dissection(void)
515 volatile tap_listener_t
*tap_queue
= tap_listener_queue
;
518 if(!(tap_queue
->flags
& TL_IS_DISSECTOR_HELPER
))
521 tap_queue
= tap_queue
->next
;
528 /* Returns TRUE there is an active tap listener for the specified tap id. */
530 have_tap_listener(int tap_id
)
532 volatile tap_listener_t
*tap_queue
= tap_listener_queue
;
535 if(tap_queue
->tap_id
== tap_id
)
538 tap_queue
= tap_queue
->next
;
545 * Return TRUE if we have any tap listeners with filters, FALSE otherwise.
548 have_filtering_tap_listeners(void)
552 for(tl
=(tap_listener_t
*)tap_listener_queue
;tl
;tl
=tl
->next
){
560 * Get the union of all the flags for all the tap listeners; that gives
561 * an indication of whether the protocol tree, or the columns, are
562 * required by any taps.
565 union_of_tap_listener_flags(void)
570 for(tl
=(tap_listener_t
*)tap_listener_queue
;tl
;tl
=tl
->next
){