/src/wireshark/epan/tap.c
Line | Count | Source |
1 | | /* tap.c |
2 | | * packet tap interface 2002 Ronnie Sahlberg |
3 | | * |
4 | | * Wireshark - Network traffic analyzer |
5 | | * By Gerald Combs <gerald@wireshark.org> |
6 | | * Copyright 1998 Gerald Combs |
7 | | * |
8 | | * SPDX-License-Identifier: GPL-2.0-or-later |
9 | | */ |
10 | | |
11 | | #include <config.h> |
12 | 0 | #define WS_LOG_DOMAIN LOG_DOMAIN_EPAN |
13 | | |
14 | | #include <stdio.h> |
15 | | |
16 | | #include <sys/types.h> |
17 | | |
18 | | #ifdef HAVE_NETINET_IN_H |
19 | | # include <netinet/in.h> |
20 | | #endif |
21 | | |
22 | | #include <string.h> |
23 | | |
24 | | #include <glib.h> |
25 | | |
26 | | #include <epan/packet_info.h> |
27 | | #include <epan/dfilter/dfilter.h> |
28 | | #include <epan/tap.h> |
29 | | #include <wsutil/wslog.h> |
30 | | |
31 | | static bool tapping_is_active=false; |
32 | | static dfilter_t *main_filter; |
33 | | |
34 | | typedef struct _tap_dissector_t { |
35 | | struct _tap_dissector_t *next; |
36 | | char *name; |
37 | | } tap_dissector_t; |
38 | | static tap_dissector_t *tap_dissector_list; |
39 | | |
40 | | /* |
41 | | * This is the list of free and used packets queued for a tap. |
42 | | * It is implemented here explicitly instead of using GLib objects |
43 | | * in order to be as fast as possible as we need to build and tear down the |
44 | | * queued list at least once for each packet we see and thus we must be able |
45 | | * to build and tear it down as fast as possible. |
46 | | * |
47 | | * XXX - some fields in packet_info get overwritten in the dissection |
48 | | * process, such as the addresses and the "this is an error packet" flag. |
49 | | * A packet may be queued at multiple protocol layers, but the packet_info |
50 | | * structure will, when the tap listeners are run, contain the values as |
51 | | * set by the topmost protocol layers. |
52 | | * |
53 | | * This means that the tap listener code can't rely on pinfo->flags.in_error_pkt |
54 | | * to determine whether the packet should be handed to the listener, as, for |
55 | | * a protocol with error report packets that include a copy of the |
56 | | * packet in error (ICMP, ICMPv6, CLNP), that flag changes during the |
57 | | * processing of the packet depending on whether we're currently dissecting |
58 | | * the packet in error or not. |
59 | | * |
60 | | * It also means that a tap listener can't depend on the source and destination |
61 | | * addresses being the correct ones for the packet being processed if, for |
62 | | * example, you have some tunneling that causes multiple layers of the same |
63 | | * protocol. |
64 | | * |
65 | | * For now, we handle the error packet flag by setting a bit in the flags |
66 | | * field of the tap_packet_t structure. We may ultimately want stacks of |
67 | | * addresses for this and other reasons. |
68 | | */ |
69 | | typedef struct _tap_packet_t { |
70 | | int tap_id; |
71 | | uint32_t flags; |
72 | | packet_info *pinfo; |
73 | | const void *tap_specific_data; |
74 | | } tap_packet_t; |
75 | | |
76 | 0 | #define TAP_PACKET_IS_ERROR_PACKET 0x00000001 /* packet being queued is an error packet */ |
77 | | |
78 | 0 | #define TAP_PACKET_QUEUE_LEN 5000 |
79 | | static tap_packet_t tap_packet_array[TAP_PACKET_QUEUE_LEN]; |
80 | | static unsigned tap_packet_index; |
81 | | |
82 | | typedef struct _tap_listener_t { |
83 | | struct _tap_listener_t *next; |
84 | | int tap_id; |
85 | | bool needs_redraw; |
86 | | bool failed; |
87 | | unsigned flags; |
88 | | char *fstring; |
89 | | dfilter_t *code; |
90 | | void *tapdata; |
91 | | tap_reset_cb reset; |
92 | | tap_packet_cb packet; |
93 | | tap_draw_cb draw; |
94 | | tap_finish_cb finish; |
95 | | } tap_listener_t; |
96 | | |
97 | | static tap_listener_t *tap_listener_queue; |
98 | | |
99 | | static GSList *tap_plugins; |
100 | | |
101 | | #ifdef HAVE_PLUGINS |
102 | | void |
103 | | tap_register_plugin(const tap_plugin *plug) |
104 | | { |
105 | | tap_plugins = g_slist_prepend(tap_plugins, (tap_plugin *)plug); |
106 | | } |
107 | | #else /* HAVE_PLUGINS */ |
108 | | void |
109 | | tap_register_plugin(const tap_plugin *plug _U_) |
110 | 0 | { |
111 | 0 | ws_warning("built without support for binary plugins"); |
112 | 0 | } |
113 | | #endif /* HAVE_PLUGINS */ |
114 | | |
115 | | static void |
116 | | call_plugin_register_tap_listener(void *data, void *user_data _U_) |
117 | 0 | { |
118 | 0 | tap_plugin *plug = (tap_plugin *)data; |
119 | |
|
120 | 0 | if (plug->register_tap_listener) { |
121 | 0 | plug->register_tap_listener(); |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | /* |
126 | | * For all taps, call their register routines. |
127 | | * |
128 | | * The table of register routines is part of the main program, not |
129 | | * part of libwireshark, so it must be passed to us as an argument. |
130 | | */ |
131 | | void |
132 | | register_all_tap_listeners(tap_reg_t const *tap_reg_listeners) |
133 | 16 | { |
134 | | /* we register the plugin taps before the other taps because |
135 | | * stats_tree taps plugins will be registered as tap listeners |
136 | | * by stats_tree_stat.c and need to registered before that */ |
137 | 16 | g_slist_foreach(tap_plugins, call_plugin_register_tap_listener, NULL); |
138 | | |
139 | 16 | if (tap_reg_listeners != NULL) |
140 | 0 | { |
141 | | /* Register all builtin listeners. */ |
142 | 0 | for (tap_reg_t const *t = &tap_reg_listeners[0]; t->cb_func != NULL; t++) { |
143 | 0 | t->cb_func(); |
144 | 0 | } |
145 | 0 | } |
146 | 16 | } |
147 | | |
148 | | /* ********************************************************************** |
149 | | * Init routine only called from epan at application startup |
150 | | * ********************************************************************** */ |
151 | | /* This function is called once when wireshark starts up and is used |
152 | | to init any data structures we may need later. |
153 | | */ |
154 | | void |
155 | | tap_init(void) |
156 | 16 | { |
157 | 16 | tap_packet_index=0; |
158 | 16 | } |
159 | | |
160 | | /* ********************************************************************** |
161 | | * Functions called from dissector when made tappable |
162 | | * ********************************************************************** */ |
163 | | /* the following two functions are used from dissectors to |
164 | | 1. register the ability to tap packets from this subdissector |
165 | | 2. push packets encountered by the subdissector to anyone tapping |
166 | | */ |
167 | | |
168 | | /* This function registers that a dissector has the packet tap ability |
169 | | available. The name parameter is the name of this tap and extensions can |
170 | | use open_tap(char *name,... to specify that it wants to receive packets/ |
171 | | events from this tap. |
172 | | |
173 | | This function is only to be called once, when the dissector initializes. |
174 | | |
175 | | The return value from this call is later used as a parameter to the |
176 | | tap_packet(unsigned int *tap_id,... |
177 | | call so that the tap subsystem knows to which tap point this tapped |
178 | | packet is associated. |
179 | | */ |
180 | | int |
181 | | register_tap(const char *name) |
182 | 2.96k | { |
183 | 2.96k | tap_dissector_t *td, *tdl = NULL, *tdl_prev = NULL; |
184 | 2.96k | int i=0; |
185 | | |
186 | 2.96k | if(tap_dissector_list){ |
187 | | /* Check if we already have the name registered, if it is return the tap_id of that tap. |
188 | | * After the for loop tdl_prev will point to the last element of the list, add the new one there. |
189 | | */ |
190 | 254k | for (i = 1, tdl = tap_dissector_list; tdl; i++, tdl_prev = tdl, tdl = tdl->next) { |
191 | 251k | if (!strcmp(tdl->name, name)) { |
192 | 176 | return i; |
193 | 176 | } |
194 | 251k | } |
195 | 2.76k | tdl = tdl_prev; |
196 | 2.76k | } |
197 | | |
198 | 2.78k | td=g_new(tap_dissector_t, 1); |
199 | 2.78k | td->next=NULL; |
200 | 2.78k | td->name = g_strdup(name); |
201 | | |
202 | 2.78k | if(!tap_dissector_list){ |
203 | 16 | tap_dissector_list=td; |
204 | 16 | i=1; |
205 | 2.76k | } else { |
206 | 2.76k | tdl->next=td; |
207 | 2.76k | } |
208 | 2.78k | return i; |
209 | 2.96k | } |
210 | | |
211 | | |
212 | | /* Every time the dissector has finished dissecting a packet (and all |
213 | | subdissectors have returned) and if the dissector has been made "tappable" |
214 | | it will push some data to everyone tapping this layer by a call |
215 | | to tap_queue_packet(). |
216 | | The first parameter is the tap_id returned by the register_tap() |
217 | | call for this dissector (so the tap system can keep track of who it came |
218 | | from and who is listening to it) |
219 | | The second is the packet_info structure which many tap readers will find |
220 | | interesting. |
221 | | The third argument is specific to each tap point or NULL if no additional |
222 | | data is available to this tap. A tap point in say IP will probably want to |
223 | | push the IP header structure here. Same thing for TCP and ONCRPC. |
224 | | |
225 | | The pinfo and the specific pointer are what is supplied to every listener |
226 | | in the read_callback() call made to every one currently listening to this |
227 | | tap. |
228 | | |
229 | | The tap reader is responsible to know how to parse any structure pointed |
230 | | to by the tap specific data pointer. |
231 | | */ |
232 | | void |
233 | | tap_queue_packet(int tap_id, packet_info *pinfo, const void *tap_specific_data) |
234 | 519k | { |
235 | 519k | tap_packet_t *tpt; |
236 | | |
237 | 519k | if(!tapping_is_active){ |
238 | 519k | return; |
239 | 519k | } |
240 | | /* |
241 | | * XXX - should we allocate this with an ep_allocator, |
242 | | * rather than having a fixed maximum number of entries? |
243 | | */ |
244 | 0 | if(tap_packet_index >= TAP_PACKET_QUEUE_LEN){ |
245 | 0 | ws_warning("Too many taps queued"); |
246 | 0 | return; |
247 | 0 | } |
248 | | |
249 | 0 | tpt=&tap_packet_array[tap_packet_index]; |
250 | 0 | tpt->tap_id=tap_id; |
251 | 0 | tpt->flags = 0; |
252 | 0 | if (pinfo->flags.in_error_pkt) |
253 | 0 | tpt->flags |= TAP_PACKET_IS_ERROR_PACKET; |
254 | 0 | tpt->pinfo=pinfo; |
255 | 0 | tpt->tap_specific_data=tap_specific_data; |
256 | 0 | tap_packet_index++; |
257 | 0 | } |
258 | | |
259 | | |
260 | | |
261 | | |
262 | | |
263 | | /* ********************************************************************** |
264 | | * Functions used by file.c to drive the tap subsystem |
265 | | * ********************************************************************** */ |
266 | | |
267 | | void tap_build_interesting (epan_dissect_t *edt) |
268 | 0 | { |
269 | 0 | tap_listener_t *tl; |
270 | 0 | bool need_protocols = false; |
271 | 0 | bool need_main_filter = false; |
272 | | |
273 | | /* nothing to do, just return */ |
274 | 0 | if(!tap_listener_queue){ |
275 | 0 | return; |
276 | 0 | } |
277 | | |
278 | | /* loop over all tap listeners and build the list of all |
279 | | interesting hf_fields */ |
280 | 0 | for(tl=tap_listener_queue;tl;tl=tl->next){ |
281 | 0 | if(tl->code){ |
282 | 0 | epan_dissect_prime_with_dfilter(edt, tl->code); |
283 | 0 | } |
284 | 0 | if(tl->flags & TL_REQUIRES_PROTOCOLS){ |
285 | 0 | need_protocols = true; |
286 | 0 | } |
287 | 0 | if(tl->flags & TL_LIMIT_TO_DISPLAY_FILTER){ |
288 | 0 | need_main_filter = true; |
289 | 0 | } |
290 | 0 | } |
291 | 0 | if (need_main_filter && main_filter) { |
292 | 0 | epan_dissect_prime_with_dfilter(edt, main_filter); |
293 | 0 | } |
294 | 0 | if (need_protocols) { |
295 | 0 | epan_dissect_fake_protocols(edt, false); |
296 | 0 | } |
297 | 0 | } |
298 | | |
299 | | /* This function is used to delete/initialize the tap queue and prime an |
300 | | epan_dissect_t with all the filters for tap listeners. |
301 | | To free the tap queue, we just prepend the used queue to the free queue. |
302 | | */ |
303 | | void |
304 | | tap_queue_init(epan_dissect_t *edt) |
305 | 0 | { |
306 | | /* nothing to do, just return */ |
307 | 0 | if(!tap_listener_queue){ |
308 | 0 | return; |
309 | 0 | } |
310 | | |
311 | 0 | tapping_is_active=true; |
312 | |
|
313 | 0 | tap_packet_index=0; |
314 | |
|
315 | 0 | tap_build_interesting (edt); |
316 | 0 | } |
317 | | |
318 | | /* this function is called after a packet has been fully dissected to push the tapped |
319 | | data to all extensions that has callbacks registered. |
320 | | */ |
321 | | void |
322 | | tap_push_tapped_queue(epan_dissect_t *edt) |
323 | 0 | { |
324 | 0 | tap_packet_t *tp; |
325 | 0 | tap_listener_t *tl; |
326 | 0 | unsigned i; |
327 | | |
328 | | /* nothing to do, just return */ |
329 | 0 | if(!tapping_is_active){ |
330 | 0 | return; |
331 | 0 | } |
332 | | |
333 | 0 | tapping_is_active=false; |
334 | | |
335 | | /* nothing to do, just return */ |
336 | 0 | if(!tap_packet_index){ |
337 | 0 | return; |
338 | 0 | } |
339 | | |
340 | | /* loop over all tap listeners and call the listener callback |
341 | | for all packets that match the filter. */ |
342 | 0 | for(i=0;i<tap_packet_index;i++){ |
343 | 0 | for(tl=tap_listener_queue;tl;tl=tl->next){ |
344 | 0 | tp=&tap_packet_array[i]; |
345 | | /* Don't tap the packet if it's an "error packet" |
346 | | * unless the listener has requested that we do so. |
347 | | */ |
348 | 0 | if (!(tp->flags & TAP_PACKET_IS_ERROR_PACKET) || (tl->flags & TL_REQUIRES_ERROR_PACKETS)) |
349 | 0 | { |
350 | 0 | if(tp->tap_id==tl->tap_id){ |
351 | 0 | if(!tl->packet){ |
352 | | /* There isn't a per-packet |
353 | | * routine for this tap. |
354 | | */ |
355 | 0 | continue; |
356 | 0 | } |
357 | 0 | if(tl->failed){ |
358 | | /* A previous call failed, |
359 | | * meaning "stop running this |
360 | | * tap", so don't call the |
361 | | * packet routine. |
362 | | */ |
363 | 0 | continue; |
364 | 0 | } |
365 | | |
366 | | /* If we have a filter, see if the |
367 | | * packet passes. |
368 | | */ |
369 | 0 | unsigned flags = tl->flags; |
370 | 0 | if((tl->flags & TL_LIMIT_TO_DISPLAY_FILTER) && main_filter) { |
371 | |
|
372 | 0 | if (!dfilter_apply_edt(main_filter, edt)){ |
373 | | /* The packet didn't |
374 | | * pass the filter. */ |
375 | 0 | if (tl->flags & TL_IGNORE_DISPLAY_FILTER) |
376 | 0 | flags |= TL_DISPLAY_FILTER_IGNORED; |
377 | 0 | else |
378 | 0 | continue; |
379 | 0 | } |
380 | 0 | } |
381 | 0 | if(tl->code){ |
382 | 0 | if (!dfilter_apply_edt(tl->code, edt)){ |
383 | | /* The packet didn't |
384 | | * pass the filter. */ |
385 | 0 | if (tl->flags & TL_IGNORE_DISPLAY_FILTER) |
386 | 0 | flags |= TL_DISPLAY_FILTER_IGNORED; |
387 | 0 | else |
388 | 0 | continue; |
389 | 0 | } |
390 | 0 | } |
391 | | |
392 | | /* So call the per-packet routine. */ |
393 | 0 | tap_packet_status status; |
394 | |
|
395 | 0 | status = tl->packet(tl->tapdata, tp->pinfo, edt, tp->tap_specific_data, flags); |
396 | |
|
397 | 0 | switch (status) { |
398 | | |
399 | 0 | case TAP_PACKET_DONT_REDRAW: |
400 | 0 | break; |
401 | | |
402 | 0 | case TAP_PACKET_REDRAW: |
403 | 0 | tl->needs_redraw=true; |
404 | 0 | break; |
405 | | |
406 | 0 | case TAP_PACKET_FAILED: |
407 | 0 | tl->failed=true; |
408 | 0 | break; |
409 | 0 | } |
410 | 0 | } |
411 | 0 | } |
412 | 0 | } |
413 | 0 | } |
414 | 0 | } |
415 | | |
416 | | |
417 | | /* This function can be used by a dissector to fetch any tapped data before |
418 | | * returning. |
419 | | * This can be useful if one wants to extract the data inside dissector BEFORE |
420 | | * it exists as an alternative to the callbacks that are all called AFTER the |
421 | | * dissection has completed. |
422 | | * |
423 | | * Example: SMB2 uses this mechanism to extract the data tapped from NTLMSSP |
424 | | * containing the account and domain names before exiting. |
425 | | * Note that the SMB2 tap listener specifies all three callbacks as NULL. |
426 | | * |
427 | | * Beware: when using this mechanism to extract the tapped data you can not |
428 | | * use "filters" and should specify the "filter" as NULL when registering |
429 | | * the tap listener. |
430 | | */ |
431 | | const void * |
432 | | fetch_tapped_data(int tap_id, int idx) |
433 | 2 | { |
434 | 2 | tap_packet_t *tp; |
435 | 2 | unsigned i; |
436 | | |
437 | | /* nothing to do, just return */ |
438 | 2 | if(!tapping_is_active){ |
439 | 2 | return NULL; |
440 | 2 | } |
441 | | |
442 | | /* nothing to do, just return */ |
443 | 0 | if(!tap_packet_index){ |
444 | 0 | return NULL; |
445 | 0 | } |
446 | | |
447 | | /* loop over all tapped packets and return the one with index idx */ |
448 | 0 | for(i=0;i<tap_packet_index;i++){ |
449 | 0 | tp=&tap_packet_array[i]; |
450 | 0 | if(tp->tap_id==tap_id){ |
451 | 0 | if(!idx--){ |
452 | 0 | return tp->tap_specific_data; |
453 | 0 | } |
454 | 0 | } |
455 | 0 | } |
456 | | |
457 | 0 | return NULL; |
458 | 0 | } |
459 | | |
460 | | /* This function is called when we need to reset all tap listeners, for example |
461 | | when we open/start a new capture or if we need to rescan the packet list. |
462 | | */ |
463 | | void |
464 | | reset_tap_listeners(void) |
465 | 0 | { |
466 | 0 | tap_listener_t *tl; |
467 | |
|
468 | 0 | for(tl=tap_listener_queue;tl;tl=tl->next){ |
469 | 0 | if(tl->reset){ |
470 | 0 | tl->reset(tl->tapdata); |
471 | 0 | } |
472 | 0 | tl->needs_redraw=true; |
473 | 0 | tl->failed=false; |
474 | 0 | } |
475 | |
|
476 | 0 | } |
477 | | |
478 | | |
479 | | /* This function is called when we need to redraw all tap listeners, for example |
480 | | when we open/start a new capture or if we need to rescan the packet list. |
481 | | It should be called from a low priority thread say once every 3 seconds |
482 | | |
483 | | If draw_all is true, redraw all applications regardless if they have |
484 | | changed or not. |
485 | | */ |
486 | | void |
487 | | draw_tap_listeners(bool draw_all) |
488 | 0 | { |
489 | 0 | tap_listener_t *tl; |
490 | |
|
491 | 0 | for(tl=tap_listener_queue;tl;tl=tl->next){ |
492 | 0 | if(tl->needs_redraw || draw_all){ |
493 | 0 | if(tl->draw){ |
494 | 0 | tl->draw(tl->tapdata); |
495 | 0 | } |
496 | 0 | } |
497 | 0 | tl->needs_redraw=false; |
498 | 0 | } |
499 | 0 | } |
500 | | |
501 | | /* Gets a GList of the tap names. The content of the list |
502 | | is owned by the tap table and should not be modified or freed. |
503 | | Use g_list_free() when done using the list. */ |
504 | | GList* |
505 | | get_tap_names(void) |
506 | 0 | { |
507 | 0 | GList *list = NULL; |
508 | 0 | tap_dissector_t *td; |
509 | |
|
510 | 0 | for(td=tap_dissector_list; td; td=td->next) { |
511 | 0 | list = g_list_prepend(list, td->name); |
512 | 0 | } |
513 | |
|
514 | 0 | return g_list_reverse(list); |
515 | 0 | } |
516 | | |
517 | | /* ********************************************************************** |
518 | | * Functions used by tap to |
519 | | * 1. register that a really simple extension is available for use by |
520 | | * Wireshark. |
521 | | * 2. start tapping from a subdissector |
522 | | * 3. close an already open tap |
523 | | * ********************************************************************** */ |
524 | | /* this function will return the tap_id for the specific protocol tap |
525 | | or 0 if no such tap was found. |
526 | | */ |
527 | | int |
528 | | find_tap_id(const char *name) |
529 | 244 | { |
530 | 244 | tap_dissector_t *td; |
531 | 244 | int i; |
532 | | |
533 | 12.9k | for(i=1,td=tap_dissector_list;td;i++,td=td->next) { |
534 | 12.9k | if(!strcmp(td->name,name)){ |
535 | 228 | return i; |
536 | 228 | } |
537 | 12.9k | } |
538 | 16 | return 0; |
539 | 244 | } |
540 | | |
541 | | static void |
542 | | free_tap_listener(tap_listener_t *tl) |
543 | 0 | { |
544 | 0 | if (tl->finish) { |
545 | 0 | tl->finish(tl->tapdata); |
546 | 0 | } |
547 | 0 | dfilter_free(tl->code); |
548 | 0 | g_free(tl->fstring); |
549 | 0 | g_free(tl); |
550 | 0 | } |
551 | | |
552 | | /* this function attaches the tap_listener to the named tap. |
553 | | * function returns : |
554 | | * NULL: ok. |
555 | | * non-NULL: error, return value points to GString containing error |
556 | | * message. |
557 | | */ |
558 | | GString * |
559 | | register_tap_listener(const char *tapname, void *tapdata, const char *fstring, |
560 | | unsigned flags, tap_reset_cb reset, tap_packet_cb packet, |
561 | | tap_draw_cb draw, tap_finish_cb finish) |
562 | 2 | { |
563 | 2 | tap_listener_t *tl; |
564 | 2 | int tap_id; |
565 | 2 | dfilter_t *code=NULL; |
566 | 2 | GString *error_string; |
567 | 2 | df_error_t *df_err; |
568 | | |
569 | 2 | tap_id=find_tap_id(tapname); |
570 | 2 | if(!tap_id){ |
571 | 0 | error_string = g_string_new(""); |
572 | 0 | g_string_printf(error_string, "Tap %s not found", tapname); |
573 | 0 | return error_string; |
574 | 0 | } |
575 | | |
576 | 2 | tl=g_new0(tap_listener_t, 1); |
577 | 2 | tl->needs_redraw=true; |
578 | 2 | tl->failed=false; |
579 | 2 | if (flags & TL_REQUIRES_PROTOCOLS) { |
580 | | /* Requiring protocols implies needing a protocol tree. |
581 | | * XXX - Warn? |
582 | | */ |
583 | 0 | flags |= TL_REQUIRES_PROTO_TREE; |
584 | 0 | } |
585 | 2 | tl->flags=flags; |
586 | 2 | if(fstring && *fstring){ |
587 | 0 | if(!dfilter_compile(fstring, &code, &df_err)){ |
588 | 0 | error_string = g_string_new(""); |
589 | 0 | g_string_printf(error_string, |
590 | 0 | "Filter \"%s\" is invalid - %s", |
591 | 0 | fstring, df_err->msg); |
592 | 0 | df_error_free(&df_err); |
593 | 0 | g_free(tl); |
594 | 0 | return error_string; |
595 | 0 | } |
596 | 0 | tl->fstring=g_strdup(fstring); |
597 | 0 | tl->code=code; |
598 | 0 | } |
599 | | |
600 | 2 | tl->tap_id=tap_id; |
601 | 2 | tl->tapdata=tapdata; |
602 | 2 | tl->reset=reset; |
603 | 2 | tl->packet=packet; |
604 | 2 | tl->draw=draw; |
605 | 2 | tl->finish=finish; |
606 | 2 | tl->next=tap_listener_queue; |
607 | | |
608 | 2 | tap_listener_queue=tl; |
609 | | |
610 | 2 | return NULL; |
611 | 2 | } |
612 | | |
613 | | /* this function sets a new dfilter to a tap listener |
614 | | */ |
615 | | GString * |
616 | | set_tap_dfilter(void *tapdata, const char *fstring) |
617 | 0 | { |
618 | 0 | tap_listener_t *tl=NULL,*tl2; |
619 | 0 | dfilter_t *code=NULL; |
620 | 0 | GString *error_string; |
621 | 0 | df_error_t *df_err; |
622 | |
|
623 | 0 | if(!tap_listener_queue){ |
624 | 0 | return NULL; |
625 | 0 | } |
626 | | |
627 | 0 | if(tap_listener_queue->tapdata==tapdata){ |
628 | 0 | tl=tap_listener_queue; |
629 | 0 | } else { |
630 | 0 | for(tl2=tap_listener_queue;tl2->next;tl2=tl2->next){ |
631 | 0 | if(tl2->next->tapdata==tapdata){ |
632 | 0 | tl=tl2->next; |
633 | 0 | break; |
634 | 0 | } |
635 | |
|
636 | 0 | } |
637 | 0 | } |
638 | |
|
639 | 0 | if(tl){ |
640 | 0 | if(tl->code){ |
641 | 0 | dfilter_free(tl->code); |
642 | 0 | tl->code=NULL; |
643 | 0 | } |
644 | 0 | tl->needs_redraw=true; |
645 | 0 | g_free(tl->fstring); |
646 | 0 | if(fstring){ |
647 | 0 | if(!dfilter_compile(fstring, &code, &df_err)){ |
648 | 0 | tl->fstring=NULL; |
649 | 0 | error_string = g_string_new(""); |
650 | 0 | g_string_printf(error_string, |
651 | 0 | "Filter \"%s\" is invalid - %s", |
652 | 0 | fstring, df_err->msg); |
653 | 0 | df_error_free(&df_err); |
654 | 0 | return error_string; |
655 | 0 | } |
656 | 0 | } |
657 | 0 | tl->fstring=g_strdup(fstring); |
658 | 0 | tl->code=code; |
659 | 0 | } |
660 | | |
661 | 0 | return NULL; |
662 | 0 | } |
663 | | |
664 | | GString * |
665 | | set_tap_flags(void *tapdata, unsigned flags) |
666 | 0 | { |
667 | | /* This never fails, and hence always returns NULL. |
668 | | * It could fail on an unknown flag, but that's a |
669 | | * programming error, not a runtime error (a bad filter |
670 | | * above can be a runtime error. Also like the above, |
671 | | * there's no failure notification on an unknown listener. |
672 | | */ |
673 | 0 | tap_listener_t *tl=NULL,*tl2; |
674 | |
|
675 | 0 | if(!tap_listener_queue){ |
676 | 0 | return NULL; |
677 | 0 | } |
678 | | |
679 | 0 | if(tap_listener_queue->tapdata==tapdata){ |
680 | 0 | tl=tap_listener_queue; |
681 | 0 | } else { |
682 | 0 | for(tl2=tap_listener_queue;tl2->next;tl2=tl2->next){ |
683 | 0 | if(tl2->next->tapdata==tapdata){ |
684 | 0 | tl=tl2->next; |
685 | 0 | break; |
686 | 0 | } |
687 | |
|
688 | 0 | } |
689 | 0 | } |
690 | |
|
691 | 0 | if(tl && tl->flags != flags) { |
692 | 0 | tl->needs_redraw=true; |
693 | 0 | tl->flags=flags; |
694 | 0 | } |
695 | |
|
696 | 0 | return NULL; |
697 | 0 | } |
698 | | |
699 | | /* this function recompiles dfilter for all registered tap listeners |
700 | | */ |
701 | | void |
702 | | tap_listeners_dfilter_recompile(void) |
703 | 0 | { |
704 | 0 | tap_listener_t *tl; |
705 | 0 | dfilter_t *code; |
706 | |
|
707 | 0 | for(tl=tap_listener_queue;tl;tl=tl->next){ |
708 | 0 | if(tl->code){ |
709 | 0 | dfilter_free(tl->code); |
710 | 0 | tl->code=NULL; |
711 | 0 | } |
712 | 0 | tl->needs_redraw=true; |
713 | 0 | code=NULL; |
714 | 0 | if(tl->fstring){ |
715 | 0 | if(!dfilter_compile(tl->fstring, &code, NULL)){ |
716 | | /* Not valid, make a dfilter matching no packets */ |
717 | 0 | dfilter_compile("frame.number == 0", &code, NULL); |
718 | 0 | } |
719 | 0 | } |
720 | 0 | tl->code=code; |
721 | 0 | } |
722 | 0 | } |
723 | | |
724 | | /* this function removes a tap listener |
725 | | */ |
726 | | void |
727 | | remove_tap_listener(void *tapdata) |
728 | 0 | { |
729 | 0 | tap_listener_t *tl=NULL,*tl2; |
730 | |
|
731 | 0 | if(!tap_listener_queue){ |
732 | 0 | return; |
733 | 0 | } |
734 | | |
735 | 0 | if(tap_listener_queue->tapdata==tapdata){ |
736 | 0 | tl=tap_listener_queue; |
737 | 0 | tap_listener_queue=tap_listener_queue->next; |
738 | 0 | } else { |
739 | 0 | for(tl2=tap_listener_queue;tl2->next;tl2=tl2->next){ |
740 | 0 | if(tl2->next->tapdata==tapdata){ |
741 | 0 | tl=tl2->next; |
742 | 0 | tl2->next=tl2->next->next; |
743 | 0 | break; |
744 | 0 | } |
745 | |
|
746 | 0 | } |
747 | 0 | if(!tl) { |
748 | 0 | ws_warning("no listener found with that tap data"); |
749 | 0 | return; |
750 | 0 | } |
751 | 0 | } |
752 | 0 | free_tap_listener(tl); |
753 | 0 | } |
754 | | |
755 | | /* |
756 | | * Return true if we have one or more tap listeners that require dissection, |
757 | | * false otherwise. |
758 | | */ |
759 | | bool |
760 | | tap_listeners_require_dissection(void) |
761 | 0 | { |
762 | 0 | tap_listener_t *tap_queue = tap_listener_queue; |
763 | |
|
764 | 0 | while(tap_queue) { |
765 | 0 | if(!(tap_queue->flags & TL_IS_DISSECTOR_HELPER)) |
766 | 0 | return true; |
767 | | |
768 | 0 | tap_queue = tap_queue->next; |
769 | 0 | } |
770 | | |
771 | 0 | return false; |
772 | |
|
773 | 0 | } |
774 | | |
775 | | /* |
776 | | * Return true if we have one or more tap listeners that require the columns, |
777 | | * false otherwise. |
778 | | */ |
779 | | bool |
780 | | tap_listeners_require_columns(void) |
781 | 0 | { |
782 | 0 | tap_listener_t *tap_queue = tap_listener_queue; |
783 | |
|
784 | 0 | while(tap_queue) { |
785 | 0 | if(tap_queue->flags & TL_REQUIRES_COLUMNS) |
786 | 0 | return true; |
787 | | |
788 | 0 | if(dfilter_requires_columns(tap_queue->code)) |
789 | 0 | return true; |
790 | | |
791 | 0 | tap_queue = tap_queue->next; |
792 | 0 | } |
793 | | |
794 | 0 | return false; |
795 | |
|
796 | 0 | } |
797 | | |
798 | | /* Returns true there is an active tap listener for the specified tap id. */ |
799 | | bool |
800 | | have_tap_listener(int tap_id) |
801 | 6.23M | { |
802 | 6.23M | tap_listener_t *tap_queue = tap_listener_queue; |
803 | | |
804 | 7.88M | while(tap_queue) { |
805 | 1.64M | if(tap_queue->tap_id == tap_id) |
806 | 0 | return true; |
807 | | |
808 | 1.64M | tap_queue = tap_queue->next; |
809 | 1.64M | } |
810 | | |
811 | 6.23M | return false; |
812 | 6.23M | } |
813 | | |
814 | | /* |
815 | | * Return true if we have any tap listeners with filters, false otherwise. |
816 | | */ |
817 | | bool |
818 | | have_filtering_tap_listeners(void) |
819 | 0 | { |
820 | 0 | tap_listener_t *tl; |
821 | |
|
822 | 0 | for(tl=tap_listener_queue;tl;tl=tl->next){ |
823 | 0 | if(tl->code) |
824 | 0 | return true; |
825 | 0 | if((tl->flags & TL_LIMIT_TO_DISPLAY_FILTER) && main_filter) |
826 | 0 | return true; |
827 | 0 | } |
828 | 0 | return false; |
829 | 0 | } |
830 | | |
831 | | void |
832 | | tap_listeners_load_field_references(epan_dissect_t *edt) |
833 | 0 | { |
834 | 0 | tap_listener_t *tl; |
835 | |
|
836 | 0 | for(tl=tap_listener_queue;tl;tl=tl->next){ |
837 | 0 | if(tl->code) |
838 | 0 | dfilter_load_field_references_edt(tl->code, edt); |
839 | 0 | } |
840 | 0 | } |
841 | | |
842 | | /* |
843 | | * Get the union of all the flags for all the tap listeners; that gives |
844 | | * an indication of whether the protocol tree, or the columns, are |
845 | | * required by any taps. |
846 | | */ |
847 | | unsigned |
848 | | union_of_tap_listener_flags(void) |
849 | 0 | { |
850 | 0 | tap_listener_t *tl; |
851 | 0 | unsigned flags = 0; |
852 | |
|
853 | 0 | for(tl=tap_listener_queue;tl;tl=tl->next){ |
854 | 0 | flags|=tl->flags; |
855 | 0 | } |
856 | 0 | return flags; |
857 | 0 | } |
858 | | |
859 | | void tap_cleanup(void) |
860 | 0 | { |
861 | 0 | tap_listener_t *elem_lq; |
862 | 0 | tap_listener_t *head_lq = tap_listener_queue; |
863 | 0 | tap_dissector_t *elem_dl; |
864 | 0 | tap_dissector_t *head_dl = tap_dissector_list; |
865 | |
|
866 | 0 | while(head_lq){ |
867 | 0 | elem_lq = head_lq; |
868 | 0 | head_lq = head_lq->next; |
869 | 0 | free_tap_listener(elem_lq); |
870 | 0 | } |
871 | 0 | tap_listener_queue = NULL; |
872 | |
|
873 | 0 | while(head_dl){ |
874 | 0 | elem_dl = head_dl; |
875 | 0 | head_dl = head_dl->next; |
876 | 0 | g_free(elem_dl->name); |
877 | 0 | g_free((void *)elem_dl); |
878 | 0 | } |
879 | 0 | tap_dissector_list = NULL; |
880 | |
|
881 | 0 | g_slist_free(tap_plugins); |
882 | 0 | tap_plugins = NULL; |
883 | 0 | } |
884 | | |
885 | | void tap_load_main_filter(dfilter_t *dfcode) |
886 | 0 | { |
887 | | /* Does not take ownership. This is not const because too |
888 | | * much of the dfilter API does not accept a const dfilter_t. |
889 | | */ |
890 | 0 | main_filter = dfcode; |
891 | 0 | } |
892 | | |
893 | | /* |
894 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
895 | | * |
896 | | * Local variables: |
897 | | * c-basic-offset: 8 |
898 | | * tab-width: 8 |
899 | | * indent-tabs-mode: t |
900 | | * End: |
901 | | * |
902 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
903 | | * :indentSize=8:tabSize=8:noTabs=false: |
904 | | */ |