2 * packet tap interface 2002 Ronnie Sahlberg
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
15 #ifdef HAVE_SYS_TYPES_H
16 # include <sys/types.h>
19 #ifdef HAVE_NETINET_IN_H
20 # include <netinet/in.h>
27 #include <epan/packet_info.h>
28 #include <epan/dfilter/dfilter.h>
30 #include <wsutil/ws_printf.h> /* ws_g_warning */
31 #include <wsutil/glib-compat.h>
33 static gboolean tapping_is_active=FALSE;
35 typedef struct _tap_dissector_t {
36 struct _tap_dissector_t *next;
39 static tap_dissector_t *tap_dissector_list=NULL;
42 * This is the list of free and used packets queued for a tap.
43 * It is implemented here explicitly instead of using GLib objects
44 * in order to be as fast as possible as we need to build and tear down the
45 * queued list at least once for each packet we see and thus we must be able
46 * to build and tear it down as fast as possible.
48 * XXX - some fields in packet_info get overwritten in the dissection
49 * process, such as the addresses and the "this is an error packet" flag.
50 * A packet may be queued at multiple protocol layers, but the packet_info
51 * structure will, when the tap listeners are run, contain the values as
52 * set by the topmost protocol layers.
54 * This means that the tap listener code can't rely on pinfo->flags.in_error_pkt
55 * to determine whether the packet should be handed to the listener, as, for
56 * a protocol with error report packets that include a copy of the
57 * packet in error (ICMP, ICMPv6, CLNP), that flag changes during the
58 * processing of the packet depending on whether we're currently dissecting
59 * the packet in error or not.
62 * It also means that a tap listener can't depend on the source and destination
63 * addresses being the correct ones for the packet being processed if, for
64 * example, you have some tunneling that causes multiple layers of the same
67 * For now, we handle the error packet flag by setting a bit in the flags
68 * field of the tap_packet_t structure. We may ultimately want stacks of
69 * addresses for this and other reasons.
71 typedef struct _tap_packet_t {
75 const void *tap_specific_data;
78 #define TAP_PACKET_IS_ERROR_PACKET 0x00000001 /* packet being queued is an error packet */
80 #define TAP_PACKET_QUEUE_LEN 5000
81 static tap_packet_t tap_packet_array[TAP_PACKET_QUEUE_LEN];
82 static guint tap_packet_index;
84 typedef struct _tap_listener_t {
85 volatile struct _tap_listener_t *next;
87 gboolean needs_redraw;
96 static volatile tap_listener_t *tap_listener_queue=NULL;
99 static GSList *tap_plugins = NULL;
102 tap_register_plugin(const tap_plugin *plug)
104 tap_plugins = g_slist_prepend(tap_plugins, (tap_plugin *)plug);
108 call_plugin_register_tap_listener(gpointer data, gpointer user_data _U_)
110 tap_plugin *plug = (tap_plugin *)data;
112 if (plug->register_tap_listener) {
113 plug->register_tap_listener();
118 * For all tap plugins, call their register routines.
121 register_all_plugin_tap_listeners(void)
123 g_slist_foreach(tap_plugins, call_plugin_register_tap_listener, NULL);
125 #endif /* HAVE_PLUGINS */
127 /* **********************************************************************
128 * Init routine only called from epan at application startup
129 * ********************************************************************** */
130 /* This function is called once when wireshark starts up and is used
131 to init any data structures we may need later.
139 /* **********************************************************************
140 * Functions called from dissector when made tappable
141 * ********************************************************************** */
142 /* the following two functions are used from dissectors to
143 1. register the ability to tap packets from this subdissector
144 2. push packets encountered by the subdissector to anyone tapping
147 /* This function registers that a dissector has the packet tap ability
148 available. The name parameter is the name of this tap and extensions can
149 use open_tap(char *name,... to specify that it wants to receive packets/
150 events from this tap.
152 This function is only to be called once, when the dissector initializes.
154 The return value from this call is later used as a parameter to the
155 tap_packet(unsigned int *tap_id,...
156 call so that the tap subsystem knows to which tap point this tapped
157 packet is associated.
160 register_tap(const char *name)
162 tap_dissector_t *td, *tdl = NULL, *tdl_prev = NULL;
165 if(tap_dissector_list){
166 /* Check if we allready have the name registered, if it is return the tap_id of that tap.
167 * After the for loop tdl_prev will point to the last element of the list, add the new one there.
169 for (i = 1, tdl = tap_dissector_list; tdl; i++, tdl_prev = tdl, tdl = tdl->next) {
170 if (!strcmp(tdl->name, name)) {
177 td=(tap_dissector_t *)g_malloc(sizeof(tap_dissector_t));
179 td->name = g_strdup(name);
181 if(!tap_dissector_list){
182 tap_dissector_list=td;
191 /* Everytime the dissector has finished dissecting a packet (and all
192 subdissectors have returned) and if the dissector has been made "tappable"
193 it will push some data to everyone tapping this layer by a call
194 to tap_queue_packet().
195 The first parameter is the tap_id returned by the register_tap()
196 call for this dissector (so the tap system can keep track of who it came
197 from and who is listening to it)
198 The second is the packet_info structure which many tap readers will find
200 The third argument is specific to each tap point or NULL if no additional
201 data is available to this tap. A tap point in say IP will probably want to
202 push the IP header structure here. Same thing for TCP and ONCRPC.
204 The pinfo and the specific pointer are what is supplied to every listener
205 in the read_callback() call made to every one currently listening to this
208 The tap reader is responsible to know how to parse any structure pointed
209 to by the tap specific data pointer.
212 tap_queue_packet(int tap_id, packet_info *pinfo, const void *tap_specific_data)
216 if(!tapping_is_active){
220 * XXX - should we allocate this with an ep_allocator,
221 * rather than having a fixed maximum number of entries?
223 if(tap_packet_index >= TAP_PACKET_QUEUE_LEN){
224 ws_g_warning("Too many taps queued");
228 tpt=&tap_packet_array[tap_packet_index];
231 if (pinfo->flags.in_error_pkt)
232 tpt->flags |= TAP_PACKET_IS_ERROR_PACKET;
234 tpt->tap_specific_data=tap_specific_data;
242 /* **********************************************************************
243 * Functions used by file.c to drive the tap subsystem
244 * ********************************************************************** */
246 void tap_build_interesting (epan_dissect_t *edt)
248 volatile tap_listener_t *tl;
250 /* nothing to do, just return */
251 if(!tap_listener_queue){
255 /* loop over all tap listeners and build the list of all
256 interesting hf_fields */
257 for(tl=tap_listener_queue;tl;tl=tl->next){
259 epan_dissect_prime_with_dfilter(edt, tl->code);
264 /* This function is used to delete/initialize the tap queue and prime an
265 epan_dissect_t with all the filters for tap listeners.
266 To free the tap queue, we just prepend the used queue to the free queue.
269 tap_queue_init(epan_dissect_t *edt)
271 /* nothing to do, just return */
272 if(!tap_listener_queue){
276 tapping_is_active=TRUE;
280 tap_build_interesting (edt);
283 /* this function is called after a packet has been fully dissected to push the tapped
284 data to all extensions that has callbacks registered.
287 tap_push_tapped_queue(epan_dissect_t *edt)
290 volatile tap_listener_t *tl;
293 /* nothing to do, just return */
294 if(!tapping_is_active){
298 tapping_is_active=FALSE;
300 /* nothing to do, just return */
301 if(!tap_packet_index){
305 /* loop over all tap listeners and call the listener callback
306 for all packets that match the filter. */
307 for(i=0;i<tap_packet_index;i++){
308 for(tl=tap_listener_queue;tl;tl=tl->next){
309 tp=&tap_packet_array[i];
310 /* Don't tap the packet if it's an "error" unless the listener tells us to */
311 if (!(tp->flags & TAP_PACKET_IS_ERROR_PACKET) || (tl->flags & TL_REQUIRES_ERROR_PACKETS))
313 if(tp->tap_id==tl->tap_id){
314 gboolean passed=TRUE;
316 passed=dfilter_apply_edt(tl->code, edt);
318 if(passed && tl->packet){
319 tl->needs_redraw|=tl->packet(tl->tapdata, tp->pinfo, edt, tp->tap_specific_data);
328 /* This function can be used by a dissector to fetch any tapped data before
330 * This can be useful if one wants to extract the data inside dissector BEFORE
331 * it exists as an alternative to the callbacks that are all called AFTER the
332 * dissection has completed.
334 * Example: SMB2 uses this mechanism to extract the data tapped from NTLMSSP
335 * containing the account and domain names before exiting.
336 * Note that the SMB2 tap listener specifies all three callbacks as NULL.
338 * Beware: when using this mechanism to extract the tapped data you can not
339 * use "filters" and should specify the "filter" as NULL when registering
343 fetch_tapped_data(int tap_id, int idx)
348 /* nothing to do, just return */
349 if(!tapping_is_active){
353 /* nothing to do, just return */
354 if(!tap_packet_index){
358 /* loop over all tapped packets and return the one with index idx */
359 for(i=0;i<tap_packet_index;i++){
360 tp=&tap_packet_array[i];
361 if(tp->tap_id==tap_id){
363 return tp->tap_specific_data;
371 /* This function is called when we need to reset all tap listeners, for example
372 when we open/start a new capture or if we need to rescan the packet list.
375 reset_tap_listeners(void)
377 volatile tap_listener_t *tl;
379 for(tl=tap_listener_queue;tl;tl=tl->next){
381 tl->reset(tl->tapdata);
383 tl->needs_redraw=TRUE;
389 /* This function is called when we need to redraw all tap listeners, for example
390 when we open/start a new capture or if we need to rescan the packet list.
391 It should be called from a low priority thread say once every 3 seconds
393 If draw_all is true, redraw all aplications regardless if they have
397 draw_tap_listeners(gboolean draw_all)
399 volatile tap_listener_t *tl;
401 for(tl=tap_listener_queue;tl;tl=tl->next){
402 if(tl->needs_redraw || draw_all){
404 tl->draw(tl->tapdata);
407 tl->needs_redraw=FALSE;
411 /* Gets a GList of the tap names. The content of the list
412 is owned by the tap table and should not be modified or freed.
413 Use g_list_free() when done using the list. */
420 for(td=tap_dissector_list; td; td=td->next) {
421 list = g_list_prepend(list, td->name);
424 return g_list_reverse(list);
427 /* **********************************************************************
428 * Functions used by tap to
429 * 1. register that a really simple extension is available for use by
431 * 2. start tapping from a subdissector
432 * 3. close an already open tap
433 * ********************************************************************** */
434 /* this function will return the tap_id for the specific protocol tap
435 or 0 if no such tap was found.
438 find_tap_id(const char *name)
443 for(i=1,td=tap_dissector_list;td;i++,td=td->next) {
444 if(!strcmp(td->name,name)){
452 free_tap_listener(volatile tap_listener_t *tl)
456 dfilter_free(tl->code);
459 g_free((gpointer)tl);
463 /* this function attaches the tap_listener to the named tap.
466 * non-NULL: error, return value points to GString containing error
470 register_tap_listener(const char *tapname, void *tapdata, const char *fstring,
471 guint flags, tap_reset_cb reset, tap_packet_cb packet, tap_draw_cb draw)
473 volatile tap_listener_t *tl;
475 dfilter_t *code=NULL;
476 GString *error_string;
479 tap_id=find_tap_id(tapname);
481 error_string = g_string_new("");
482 g_string_printf(error_string, "Tap %s not found", tapname);
486 tl=(volatile tap_listener_t *)g_malloc0(sizeof(tap_listener_t));
487 tl->needs_redraw=TRUE;
490 if(!dfilter_compile(fstring, &code, &err_msg)){
491 error_string = g_string_new("");
492 g_string_printf(error_string,
493 "Filter \"%s\" is invalid - %s",
496 free_tap_listener(tl);
500 tl->fstring=g_strdup(fstring);
508 tl->next=tap_listener_queue;
510 tap_listener_queue=tl;
515 /* this function sets a new dfilter to a tap listener
518 set_tap_dfilter(void *tapdata, const char *fstring)
520 volatile tap_listener_t *tl=NULL,*tl2;
521 dfilter_t *code=NULL;
522 GString *error_string;
525 if(!tap_listener_queue){
529 if(tap_listener_queue->tapdata==tapdata){
530 tl=tap_listener_queue;
532 for(tl2=tap_listener_queue;tl2->next;tl2=tl2->next){
533 if(tl2->next->tapdata==tapdata){
543 dfilter_free(tl->code);
546 tl->needs_redraw=TRUE;
549 if(!dfilter_compile(fstring, &code, &err_msg)){
551 error_string = g_string_new("");
552 g_string_printf(error_string,
553 "Filter \"%s\" is invalid - %s",
559 tl->fstring=g_strdup(fstring);
566 /* this function recompiles dfilter for all registered tap listeners
569 tap_listeners_dfilter_recompile(void)
571 volatile tap_listener_t *tl;
575 for(tl=tap_listener_queue;tl;tl=tl->next){
577 dfilter_free(tl->code);
580 tl->needs_redraw=TRUE;
583 if(!dfilter_compile(tl->fstring, &code, &err_msg)){
586 /* Not valid, make a dfilter matching no packets */
587 if (!dfilter_compile("frame.number == 0", &code, &err_msg))
595 /* this function removes a tap listener
598 remove_tap_listener(void *tapdata)
600 volatile tap_listener_t *tl=NULL,*tl2;
602 if(!tap_listener_queue){
606 if(tap_listener_queue->tapdata==tapdata){
607 tl=tap_listener_queue;
608 tap_listener_queue=tap_listener_queue->next;
610 for(tl2=tap_listener_queue;tl2->next;tl2=tl2->next){
611 if(tl2->next->tapdata==tapdata){
613 tl2->next=tl2->next->next;
619 free_tap_listener(tl);
623 * Return TRUE if we have one or more tap listeners that require dissection,
627 tap_listeners_require_dissection(void)
629 volatile tap_listener_t *tap_queue = tap_listener_queue;
632 if(!(tap_queue->flags & TL_IS_DISSECTOR_HELPER))
635 tap_queue = tap_queue->next;
642 /* Returns TRUE there is an active tap listener for the specified tap id. */
644 have_tap_listener(int tap_id)
646 volatile tap_listener_t *tap_queue = tap_listener_queue;
649 if(tap_queue->tap_id == tap_id)
652 tap_queue = tap_queue->next;
659 * Return TRUE if we have any tap listeners with filters, FALSE otherwise.
662 have_filtering_tap_listeners(void)
664 volatile tap_listener_t *tl;
666 for(tl=tap_listener_queue;tl;tl=tl->next){
674 * Get the union of all the flags for all the tap listeners; that gives
675 * an indication of whether the protocol tree, or the columns, are
676 * required by any taps.
679 union_of_tap_listener_flags(void)
681 volatile tap_listener_t *tl;
684 for(tl=tap_listener_queue;tl;tl=tl->next){
690 void tap_cleanup(void)
692 volatile tap_listener_t *elem_lq;
693 volatile tap_listener_t *head_lq = tap_listener_queue;
694 tap_dissector_t *elem_dl;
695 tap_dissector_t *head_dl = tap_dissector_list;
699 head_lq = head_lq->next;
700 free_tap_listener(elem_lq);
705 head_dl = head_dl->next;
706 g_free((char*)elem_dl->name);
707 g_free((gpointer)elem_dl);
711 g_slist_free(tap_plugins);
713 #endif /* HAVE_PLUGINS */
717 * Editor modelines - http://www.wireshark.org/tools/modelines.html
722 * indent-tabs-mode: t
725 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
726 * :indentSize=8:tabSize=8:noTabs=false: