4 * Wireshark's interface to the Lua Programming Language
6 * Implementation of tap Listeners
8 * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
18 #define WS_LOG_DOMAIN LOG_DOMAIN_WSLUA
20 /* WSLUA_MODULE Listener Post-Dissection Packet Analysis */
24 WSLUA_CLASS_DEFINE(Listener
,FAIL_ON_NULL("Listener"));
26 A `Listener` is called once for every packet that matches a certain filter or has a certain tap.
27 It can read the tree, the packet's <<lua_class_Tvb,`Tvb`>> buffer as well as the tapped data, but it cannot add elements to the tree.
30 static int tap_packet_cb_error_handler(lua_State
* L
) {
31 const char* error
= lua_tostring(L
,1);
32 static char* last_error
= NULL
;
33 static int repeated
= 0;
35 char* where
= (lua_pinfo
) ?
36 wmem_strdup_printf(NULL
, "Lua: on packet %i Error during execution of Listener packet callback",lua_pinfo
->num
) :
37 wmem_strdup_printf(NULL
, "Lua: Error during execution of Listener packet callback") ;
39 /* show the error the 1st, 3rd, 5th, 9th, 17th, 33th... time it appears to avoid window flooding */
40 /* XXX the last series of identical errors won't be shown (the user however gets at least one message) */
43 report_failure("%s:\n%s",where
,error
);
44 last_error
= g_strdup(error
);
47 wmem_free(NULL
, where
);
51 if (g_str_equal(last_error
,error
) ) {
53 if ( repeated
== next
) {
54 report_failure("%s happened %i times:\n %s",where
,repeated
,error
);
58 report_failure("%s happened %i times:\n %s",where
,repeated
,last_error
);
60 last_error
= g_strdup(error
);
63 report_failure("%s:\n %s",where
,error
);
66 wmem_free(NULL
, where
);
71 static tap_packet_status
lua_tap_packet(void *tapdata
, packet_info
*pinfo
, epan_dissect_t
*edt
, const void *data
, tap_flags_t flags _U_
) {
72 Listener tap
= (Listener
)tapdata
;
73 tap_packet_status retval
= TAP_PACKET_DONT_REDRAW
;
74 TreeItem lua_tree_tap
;
76 if (tap
->packet_ref
== LUA_NOREF
) return TAP_PACKET_DONT_REDRAW
; /* XXX - report error and return TAP_PACKET_FAILED? */
79 lua_pushcfunction(tap
->L
,tap_packet_cb_error_handler
);
80 lua_rawgeti(tap
->L
, LUA_REGISTRYINDEX
, tap
->packet_ref
);
82 push_Pinfo(tap
->L
, pinfo
);
83 push_Tvb(tap
->L
, edt
->tvb
);
86 tap
->extractor(tap
->L
,data
);
93 lua_tree_tap
= create_TreeItem(edt
->tree
, NULL
);
94 lua_tree
= lua_tree_tap
;
96 switch ( lua_pcall(tap
->L
,3,1,1) ) {
98 /* XXX - treat 2 as TAP_PACKET_FAILED? */
99 retval
= luaL_optinteger(tap
->L
,-1,1) == 0 ? TAP_PACKET_DONT_REDRAW
: TAP_PACKET_REDRAW
;
102 /* XXX - TAP_PACKET_FAILED? */
105 ws_warning("Memory alloc error while calling listener tap callback packet");
106 /* XXX - TAP_PACKET_FAILED? */
109 ws_warning("Error while running the error handler function for listener tap callback");
112 ws_assert_not_reached();
116 clear_outstanding_Pinfo();
117 clear_outstanding_Tvb();
122 g_free(lua_tree_tap
);
127 static int tap_reset_cb_error_handler(lua_State
* L
) {
128 const char* error
= lua_tostring(L
,1);
129 report_failure("Lua: Error during execution of Listener reset callback:\n %s",error
);
133 static void lua_tap_reset(void *tapdata
) {
134 Listener tap
= (Listener
)tapdata
;
136 if (tap
->reset_ref
== LUA_NOREF
) return;
138 lua_pushcfunction(tap
->L
,tap_reset_cb_error_handler
);
139 lua_rawgeti(tap
->L
, LUA_REGISTRYINDEX
, tap
->reset_ref
);
141 switch ( lua_pcall(tap
->L
,0,0,lua_gettop(tap
->L
)-1) ) {
145 ws_warning("Runtime error while calling a listener's init()");
148 ws_warning("Memory alloc error while calling a listener's init()");
151 ws_warning("Error while running the error handler function for a listener's init()");
154 ws_assert_not_reached();
159 static int tap_draw_cb_error_handler(lua_State
* L
) {
160 const char* error
= lua_tostring(L
,1);
161 report_failure("Lua: Error during execution of Listener draw callback:\n %s",error
);
165 static void lua_tap_draw(void *tapdata
) {
166 Listener tap
= (Listener
)tapdata
;
169 if (tap
->draw_ref
== LUA_NOREF
) return;
171 lua_pushcfunction(tap
->L
,tap_draw_cb_error_handler
);
172 lua_rawgeti(tap
->L
, LUA_REGISTRYINDEX
, tap
->draw_ref
);
174 switch ( lua_pcall(tap
->L
,0,0,lua_gettop(tap
->L
)-1) ) {
179 error
= lua_tostring(tap
->L
,-1);
180 ws_warning("Runtime error while calling a listener's draw(): %s",error
);
183 ws_warning("Memory alloc error while calling a listener's draw()");
186 ws_warning("Error while running the error handler function for a listener's draw()");
189 ws_assert_not_reached();
194 /* TODO: we should probably use a Lua table here */
195 static GPtrArray
*listeners
;
197 static void deregister_Listener (lua_State
* L _U_
, Listener tap
) {
198 if (tap
->all_fields
) {
199 epan_set_always_visible(false);
200 tap
->all_fields
= false;
203 remove_tap_listener(tap
);
210 WSLUA_CONSTRUCTOR
Listener_new(lua_State
* L
) {
211 /* Creates a new `Listener` tap object. */
212 #define WSLUA_OPTARG_Listener_new_TAP 1 /* The name of this tap. See <<lua_fn_Listener_list__,`Listener.list()`>> for a way to print valid listener names. */
213 #define WSLUA_OPTARG_Listener_new_FILTER 2 /*
214 A display filter to apply to the tap.
215 The `tap.packet` function will be called for each matching packet.
216 The default is `nil`, which matches every packet.
219 #define WSLUA_OPTARG_Listener_new_ALLFIELDS 3 /*
220 Whether to generate all fields.
221 The default is `false`.
222 Note: This impacts performance. */
224 const char* tap_type
= luaL_optstring(L
,WSLUA_OPTARG_Listener_new_TAP
,"frame");
225 const char* filter
= luaL_optstring(L
,WSLUA_OPTARG_Listener_new_FILTER
,NULL
);
226 const bool all_fields
= wslua_optbool(L
, WSLUA_OPTARG_Listener_new_ALLFIELDS
, false);
230 tap
= (Listener
)g_malloc(sizeof(struct _wslua_tap
));
232 tap
->name
= g_strdup(tap_type
);
233 tap
->filter
= g_strdup(filter
);
234 tap
->extractor
= wslua_get_tap_extractor(tap_type
);
236 tap
->packet_ref
= LUA_NOREF
;
237 tap
->draw_ref
= LUA_NOREF
;
238 tap
->reset_ref
= LUA_NOREF
;
239 tap
->all_fields
= all_fields
;
242 * XXX - do all Lua taps require the protocol tree? If not, it might
243 * be useful to have a way to indicate whether any do.
245 * XXX - do any Lua taps require the columns? If so, we either need
246 * to request them for this tap, or do so if any Lua taps require them.
248 error
= register_tap_listener(tap_type
, tap
, tap
->filter
, TL_REQUIRES_PROTO_TREE
, lua_tap_reset
, lua_tap_packet
, lua_tap_draw
, NULL
);
254 /* WSLUA_ERROR(new_tap,"tap registration error"); */
255 lua_pushfstring(L
,"Error while registering tap:\n%s",error
->str
);
256 g_string_free(error
,TRUE
);
257 return luaL_error(L
,lua_tostring(L
,-1));
261 epan_set_always_visible(true);
264 g_ptr_array_add(listeners
, tap
);
267 WSLUA_RETURN(1); /* The newly created Listener listener object */
270 /* Allow dissector key names to be sorted alphabetically */
272 compare_dissector_key_name(const void *dissector_a
, const void *dissector_b
)
274 return strcmp((const char*)dissector_a
, (const char*)dissector_b
);
277 WSLUA_CONSTRUCTOR
Listener_list (lua_State
*L
) { /*
278 Gets a Lua array table of all registered `Listener` tap names.
280 Note: This is an expensive operation, and should only be used for troubleshooting.
285 -- Print a list of tap listeners to stdout.
286 for _,tap_name in pairs(Listener.list()) do
291 GList
* list
= get_tap_names();
295 if (!list
) return luaL_error(L
,"Cannot retrieve tap name list");
297 list
= g_list_sort(list
, (GCompareFunc
)compare_dissector_key_name
);
298 elist
= g_list_first(list
);
301 for (i
=1; elist
; i
++, elist
= g_list_next(elist
)) {
302 lua_pushstring(L
,(const char *) elist
->data
);
307 WSLUA_RETURN(1); /* The array table of registered tap names */
310 WSLUA_METHOD
Listener_remove(lua_State
* L
) {
311 /* Removes a tap `Listener`. */
312 Listener tap
= checkListener(L
,1);
314 if (listeners
&& g_ptr_array_remove(listeners
, tap
)) {
315 deregister_Listener(L
, tap
);
321 WSLUA_METAMETHOD
Listener__tostring(lua_State
* L
) {
322 /* Generates a string of debug info for the tap `Listener`. */
323 Listener tap
= checkListener(L
,1);
325 lua_pushfstring(L
,"Listener(%s) filter: %s tapinfo: %s",tap
->name
, tap
->filter
? tap
->filter
: "NONE", tap
->extractor
? "YES": "NO");
331 /* WSLUA_ATTRIBUTE Listener_packet WO A function that will be called once every packet matches the
332 `Listener` listener filter.
334 When later called by Wireshark, the `packet` function will be given:
341 function tap.packet(pinfo,tvb,tapinfo) ... end
346 `tapinfo` is a table of info based on the `Listener` type, or nil.
348 See _epan/wslua/taps_ for `tapinfo` structure definitions.
351 WSLUA_ATTRIBUTE_FUNC_SETTER(Listener
,packet
);
354 /* WSLUA_ATTRIBUTE Listener_draw WO A function that will be called once every few seconds to redraw the GUI objects;
355 in TShark this function is called only at the very end of the capture file.
357 When later called by Wireshark, the `draw` function will not be given any arguments.
361 function tap.draw() ... end
364 WSLUA_ATTRIBUTE_FUNC_SETTER(Listener
,draw
);
366 /* WSLUA_ATTRIBUTE Listener_reset WO A function that will be called at the end of the capture run.
368 When later called by Wireshark, the `reset` function will not be given any arguments.
372 function tap.reset() ... end
375 WSLUA_ATTRIBUTE_FUNC_SETTER(Listener
,reset
);
378 static int Listener__gc(lua_State
* L _U_
) {
379 /* do NOT free Listener here, only in deregister_Listener */
383 /* This table is ultimately registered as a sub-table of the class' metatable,
384 * and if __index/__newindex is invoked then it calls the appropriate function
385 * from this table for getting/setting the members.
387 WSLUA_ATTRIBUTES Listener_attributes
[] = {
388 WSLUA_ATTRIBUTE_WOREG(Listener
,packet
),
389 WSLUA_ATTRIBUTE_WOREG(Listener
,draw
),
390 WSLUA_ATTRIBUTE_WOREG(Listener
,reset
),
394 WSLUA_METHODS Listener_methods
[] = {
395 WSLUA_CLASS_FNREG(Listener
,new),
396 WSLUA_CLASS_FNREG(Listener
,remove
),
397 WSLUA_CLASS_FNREG(Listener
,list
),
401 WSLUA_META Listener_meta
[] = {
402 WSLUA_CLASS_MTREG(Listener
,tostring
),
406 int Listener_register(lua_State
* L
) {
407 wslua_set_tap_enums(L
);
409 listeners
= g_ptr_array_new();
411 WSLUA_REGISTER_CLASS_WITH_ATTRS(Listener
);
415 static void deregister_tap_listener (void *data
, void *userdata
) {
416 lua_State
*L
= (lua_State
*) userdata
;
417 Listener tap
= (Listener
) data
;
418 deregister_Listener(L
, tap
);
421 int wslua_deregister_listeners(lua_State
* L
) {
422 g_ptr_array_foreach(listeners
, deregister_tap_listener
, L
);
423 g_ptr_array_free(listeners
, true);
430 * Editor modelines - https://www.wireshark.org/tools/modelines.html
435 * indent-tabs-mode: nil
438 * vi: set shiftwidth=4 tabstop=8 expandtab:
439 * :indentSize=4:tabSize=8:noTabs=true: