diff --git a/epan/epan.c b/epan/epan.c index 2a9533fc89..85c09ab474 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -229,6 +229,21 @@ epan_circuit_cleanup(void) circuit_cleanup(); } +/* Overrides proto_tree_visible i epan_dissect_init to make all fields visible. + * This is > 0 if a Lua script wanted to see all fields all the time. + * This is ref-counted, so clearing it won't override other taps/scripts wanting it. + */ +static gint always_visible_refcount = 0; + +void +epan_set_always_visible(gboolean force) +{ + if (force) + always_visible_refcount++; + else if (always_visible_refcount > 0) + always_visible_refcount--; +} + epan_dissect_t* epan_dissect_init(epan_dissect_t *edt, epan_t *session, const gboolean create_proto_tree, const gboolean proto_tree_visible) { @@ -247,7 +262,7 @@ epan_dissect_init(epan_dissect_t *edt, epan_t *session, const gboolean create_pr if (create_proto_tree) { edt->tree = proto_tree_create_root(&edt->pi); - proto_tree_set_visible(edt->tree, proto_tree_visible); + proto_tree_set_visible(edt->tree, (always_visible_refcount > 0) ? TRUE : proto_tree_visible); } else { edt->tree = NULL; diff --git a/epan/epan.h b/epan/epan.h index 5a9dbda019..a50ee8d548 100644 --- a/epan/epan.h +++ b/epan/epan.h @@ -145,6 +145,18 @@ WS_DLL_PUBLIC void epan_free(epan_t *session); WS_DLL_PUBLIC const gchar* epan_get_version(void); +/** + * Set/unset the tree to always be visible when epan_dissect_init() is called. + * This state change sticks until cleared, rather than being done per function call. + * This is currently used when Lua scripts request all fields be generated. + * By default it only becomes visible if epan_dissect_init() makes it so, usually + * only when a packet is selected. + * Setting this overrides that so it's always visible, although it will still not be + * created if create_proto_tree is false in the call to epan_dissect_init(). + * Clearing this reverts the decision to epan_dissect_init() and proto_tree_visible. + */ +void epan_set_always_visible(gboolean force); + /** initialize an existing single packet dissection */ WS_DLL_PUBLIC epan_dissect_t* diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h index 2f48ca3d34..05045e3a5f 100644 --- a/epan/wslua/wslua.h +++ b/epan/wslua/wslua.h @@ -199,6 +199,7 @@ struct _wslua_tap { int packet_ref; int draw_ref; int reset_ref; + gboolean all_fields; }; # define DIRECTORY_T GDir diff --git a/epan/wslua/wslua_listener.c b/epan/wslua/wslua_listener.c index d504f52e9d..14438631e2 100644 --- a/epan/wslua/wslua_listener.c +++ b/epan/wslua/wslua_listener.c @@ -192,9 +192,11 @@ WSLUA_CONSTRUCTOR Listener_new(lua_State* L) { /* Creates a new Listener listener */ #define WSLUA_OPTARG_Listener_new_TAP 1 /* The name of this tap */ #define WSLUA_OPTARG_Listener_new_FILTER 2 /* A filter that when matches the tap.packet function gets called (use nil to be called for every packet) */ +#define WSLUA_OPTARG_Listener_new_ALLFIELDS 3 /* Whether to generate all fields. Note: this impacts performance (default=false) */ const gchar* tap_type = luaL_optstring(L,WSLUA_OPTARG_Listener_new_TAP,"frame"); const gchar* filter = luaL_optstring(L,WSLUA_OPTARG_Listener_new_FILTER,NULL); + const gboolean all_fields = wslua_optbool(L, WSLUA_OPTARG_Listener_new_ALLFIELDS, FALSE); Listener tap; GString* error; @@ -207,6 +209,7 @@ WSLUA_CONSTRUCTOR Listener_new(lua_State* L) { tap->packet_ref = LUA_NOREF; tap->draw_ref = LUA_NOREF; tap->reset_ref = LUA_NOREF; + tap->all_fields = all_fields; /* * XXX - do all Lua taps require the protocol tree? If not, it might @@ -226,6 +229,10 @@ WSLUA_CONSTRUCTOR Listener_new(lua_State* L) { g_string_free(error,TRUE); /* XXX LEAK? */ } + if (all_fields) { + epan_set_always_visible(TRUE); + } + pushListener(L,tap); WSLUA_RETURN(1); /* The newly created Listener listener object */ } @@ -263,6 +270,11 @@ WSLUA_METHOD Listener_remove(lua_State* L) { /* Removes a tap listener */ Listener tap = checkListener(L,1); + if (tap->all_fields) { + epan_set_always_visible(FALSE); + tap->all_fields = FALSE; + } + remove_tap_listener(tap); return 0; diff --git a/epan/wslua/wslua_proto.c b/epan/wslua/wslua_proto.c index 4069b846ea..573cd9740b 100644 --- a/epan/wslua/wslua_proto.c +++ b/epan/wslua/wslua_proto.c @@ -1403,8 +1403,6 @@ static int Proto__tostring(lua_State* L) { Proto proto = checkProto(L,1); gchar* s; - if (!proto) return 0; - s = ep_strdup_printf("Proto: %s",proto->name); lua_pushstring(L,s); @@ -1414,8 +1412,10 @@ static int Proto__tostring(lua_State* L) { WSLUA_FUNCTION wslua_register_postdissector(lua_State* L) { /* Make a protocol (with a dissector) a postdissector. It will be called for every frame after dissection */ #define WSLUA_ARG_register_postdissector_PROTO 1 /* the protocol to be used as postdissector */ +#define WSLUA_OPTARG_register_postdissector_ALLFIELDS 2 /* Whether to generate all fields. Note: this impacts performance (default=false) */ + Proto proto = checkProto(L,WSLUA_ARG_register_postdissector_PROTO); - if (!proto) return 0; + const gboolean all_fields = wslua_optbool(L, WSLUA_OPTARG_register_postdissector_ALLFIELDS, FALSE); if(!proto->is_postdissector) { if (! proto->handle) { @@ -1427,6 +1427,10 @@ WSLUA_FUNCTION wslua_register_postdissector(lua_State* L) { luaL_argerror(L,1,"this protocol is already registered as postdissector"); } + if (all_fields) { + epan_set_always_visible(TRUE); + } + return 0; } diff --git a/test/lua/listener.lua b/test/lua/listener.lua index ecb1a52a3f..55873fbbab 100644 --- a/test/lua/listener.lua +++ b/test/lua/listener.lua @@ -8,6 +8,7 @@ local ETH = "eth" local IP = "ip" local BOOTP = "bootp" local OTHER = "other" +local PDISS = "postdissector" local packet_counts = {} local function incPktCount(name) @@ -34,7 +35,7 @@ end -- note ip only runs 3 times because it gets removed -- and bootp only runs twice because the filter makes it run -- once and then it gets replaced with a different one for the second time -local taptests = { [FRAME]=4, [ETH]=4, [IP]=3, [BOOTP]=2, [OTHER]=15 } +local taptests = { [FRAME]=4, [ETH]=4, [IP]=3, [BOOTP]=2, [OTHER]=16 } local function getResults() print("\n-----------------------------\n") for k,v in pairs(taptests) do @@ -64,6 +65,49 @@ local function test(type,name, ...) end end +local pkt_fields = { [FRAME] = {}, [PDISS] = {} } +local function getAllFieldInfos(type) + local fields = { all_field_infos() } + local fieldnames = {} + for i,v in ipairs(fields) do + fieldnames[i] = v.name + end + local pktnum = getPktCount(type) + pkt_fields[type][pktnum] = { ["num"] = #fields, ["fields"] = fieldnames } +end + +local function dumpAllFieldInfos() + for i,v in ipairs(pkt_fields[FRAME]) do + print("In frame tap for packet ".. i ..":") + print(" number of fields = ".. v.num) + for _,name in ipairs(v.fields) do + print(" field = ".. name) + end + local w = pkt_fields[PDISS][i] + print("In postdissector for packet ".. i ..":") + print(" number of fields = ".. w.num) + for _,name in ipairs(w.fields) do + print(" field = ".. name) + end + end +end + +local function checkAllFieldInfos() + for i,v in ipairs(pkt_fields[FRAME]) do + local numfields = v.num + if numfields ~= pkt_fields[PDISS][i].num then + print("Tap and postdissector do not have same number of fields!") + return false + end + if numfields < 100 then + print("Too few fields!") + return false + end + end + return true +end + + --------- -- the following are so we can use pcall (which needs a function to call) local function makeListener(...) @@ -124,7 +168,7 @@ local f_ip_dst = Field.new("ip.dst") local f_bootp_hw = Field.new("bootp.hw.mac_addr") local f_bootp_opt = Field.new("bootp.option.type") -local tap_frame = Listener.new() +local tap_frame = Listener.new(nil,nil,true) local tap_eth = Listener.new("eth") local tap_ip = Listener.new("ip","bootp") local tap_bootp = Listener.new("bootp","bootp.option.dhcp == 1") @@ -146,6 +190,8 @@ function tap_frame.packet(pinfo,tvb,frame) local eth_src2 = tostring(tvb:range(6,6)) test(FRAME,"FieldInfo.range-1", eth_src1 == eth_src2) + getAllFieldInfos(FRAME) + setPassed(FRAME) end @@ -221,13 +267,34 @@ tap_bootp.packet = bootp_packet function tap_frame.reset() -- reset never gets called in tshark (sadly) - error("reset called!!") + if not GUI_ENABLED then + error("reset called!!") + end end function tap_frame.draw() + test(OTHER,"all_field_infos", checkAllFieldInfos()) + setPassed(OTHER) getResults() end - +-- max_gap.lua +-- create a gap.max field containing the maximum gap between two packets between two ip nodes + +-- we create a "protocol" for our tree +local max_gap_p = Proto("gap","Gap in IP conversations") + +-- we create our fields +local max_gap_field = ProtoField.float("gap.max") + +-- we add our fields to the protocol +max_gap_p.fields = { max_gap_field } + +-- then we register max_gap_p as a postdissector +register_postdissector(max_gap_p,true) +function max_gap_p.dissector(tvb,pinfo,tree) + incPktCount(PDISS) + getAllFieldInfos(PDISS) +end