diff options
author | Hadriel Kaplan <hadrielk@yahoo.com> | 2015-01-25 14:30:13 -0500 |
---|---|---|
committer | Hadriel Kaplan <hadrielk@yahoo.com> | 2015-01-27 15:14:12 +0000 |
commit | ceb8d954d25211d5cb4766ece277c15aa53578d5 (patch) | |
tree | 859ad1b08e44c140728311e9ed60fd3444cd2054 /epan/wslua | |
parent | 9bbc33730622e117d9edfa3f393da883624510f1 (diff) |
Lua: Expose tcp_dissect_pdus() to Lua
Provide a way for Lua-based dissectors to invoke tcp_dissect_pdus()
to make TCP-based dissection easier.
Bug: 9851
Change-Id: I91630ebf1f1fc1964118b6750cc34238e18a8ad3
Reviewed-on: https://code.wireshark.org/review/6778
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Reviewed-by: Hadriel Kaplan <hadrielk@yahoo.com>
Tested-by: Hadriel Kaplan <hadrielk@yahoo.com>
Diffstat (limited to 'epan/wslua')
-rw-r--r-- | epan/wslua/init_wslua.c | 11 | ||||
-rw-r--r-- | epan/wslua/wslua.h | 4 | ||||
-rw-r--r-- | epan/wslua/wslua_listener.c | 5 | ||||
-rw-r--r-- | epan/wslua/wslua_proto.c | 172 | ||||
-rw-r--r-- | epan/wslua/wslua_tree.c | 20 |
5 files changed, 192 insertions, 20 deletions
diff --git a/epan/wslua/init_wslua.c b/epan/wslua/init_wslua.c index 7b8399da0f..6e044ea811 100644 --- a/epan/wslua/init_wslua.c +++ b/epan/wslua/init_wslua.c @@ -142,6 +142,7 @@ lua_pinfo_end(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U_, clear_outstanding_PrivateTable(); clear_outstanding_TreeItem(); clear_outstanding_FieldInfo(); + clear_outstanding_FuncSavers(); /* keep invoking this callback later? */ return FALSE; @@ -162,10 +163,7 @@ int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data lua_pinfo = pinfo; lua_tvb = tvb; - lua_tree = (struct _wslua_treeitem *)g_malloc(sizeof(struct _wslua_treeitem)); - lua_tree->tree = tree; - lua_tree->item = proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA); - lua_tree->expired = FALSE; + lua_tree = create_TreeItem(tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA)); PROTO_ITEM_SET_HIDDEN(lua_tree->item); /* @@ -280,10 +278,7 @@ gboolean heur_dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, v return FALSE; } - lua_tree = (struct _wslua_treeitem *)g_malloc(sizeof(struct _wslua_treeitem)); - lua_tree->tree = tree; - lua_tree->item = proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA); - lua_tree->expired = FALSE; + lua_tree = create_TreeItem(tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA)); PROTO_ITEM_SET_HIDDEN(lua_tree->item); push_Tvb(L,tvb); diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h index 9fe25bfcf8..8413e94046 100644 --- a/epan/wslua/wslua.h +++ b/epan/wslua/wslua.h @@ -686,6 +686,10 @@ extern void lua_prime_all_fields(proto_tree* tree); extern int Proto_commit(lua_State* L); +extern TreeItem create_TreeItem(proto_tree* tree, proto_item* item); + +extern void clear_outstanding_FuncSavers(void); + extern void Int64_pack(lua_State* L, luaL_Buffer *b, gint idx, gboolean asLittleEndian); extern int Int64_unpack(lua_State* L, const gchar *buff, gboolean asLittleEndian); extern void UInt64_pack(lua_State* L, luaL_Buffer *b, gint idx, gboolean asLittleEndian); diff --git a/epan/wslua/wslua_listener.c b/epan/wslua/wslua_listener.c index 3f7767d347..c7feb6595e 100644 --- a/epan/wslua/wslua_listener.c +++ b/epan/wslua/wslua_listener.c @@ -103,10 +103,7 @@ static int lua_tap_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt lua_pinfo = pinfo; lua_tvb = edt->tvb; - lua_tree = (struct _wslua_treeitem *)g_malloc(sizeof(struct _wslua_treeitem)); - lua_tree->tree = edt->tree; - lua_tree->item = NULL; - lua_tree->expired = FALSE; + lua_tree = create_TreeItem(edt->tree, NULL); switch ( lua_pcall(tap->L,3,1,1) ) { case 0: diff --git a/epan/wslua/wslua_proto.c b/epan/wslua/wslua_proto.c index 309c6d7ce7..2a4197a7ba 100644 --- a/epan/wslua/wslua_proto.c +++ b/epan/wslua/wslua_proto.c @@ -43,6 +43,7 @@ */ #include "wslua.h" +#include <epan/dissectors/packet-tcp.h> #include <epan/exceptions.h> #include <epan/show_exception.h> @@ -2069,6 +2070,176 @@ int Proto_commit(lua_State* L) { return 0; } +typedef struct _func_saver { + lua_State* state; + int get_len_ref; + int dissect_ref; +} func_saver_t; + +static GPtrArray* outstanding_FuncSavers = NULL; + +void clear_outstanding_FuncSavers(void) { + while (outstanding_FuncSavers->len) { + func_saver_t* fs = (func_saver_t*)g_ptr_array_remove_index_fast(outstanding_FuncSavers,0); + if (fs->state) { + lua_State* L = fs->state; + if (fs->get_len_ref != LUA_NOREF) { + luaL_unref(L, LUA_REGISTRYINDEX, fs->get_len_ref); + } + if (fs->dissect_ref != LUA_NOREF) { + luaL_unref(L, LUA_REGISTRYINDEX, fs->dissect_ref); + } + } + g_free(fs); + } +} + +static guint +wslua_dissect_tcp_get_pdu_len(packet_info *pinfo, tvbuff_t *tvb, + int offset, void *data _U_) +{ + func_saver_t* fs = (func_saver_t*)data; + lua_State* L = fs->state; + int pdu_len = 0; + + lua_settop(L, 0); + lua_rawgeti(L, LUA_REGISTRYINDEX, fs->get_len_ref); + + if (lua_isfunction(L,1)) { + + push_Tvb(L,tvb); + push_Pinfo(L,pinfo); + lua_pushinteger(L,offset); + + if ( lua_pcall(L,3,1,0) ) { + luaL_error(L, "Lua Error in dissect_tcp_pdus get_len_func: %s", lua_tostring(L,-1)); + } else { + /* if the Lua dissector reported the consumed bytes, pass it to our caller */ + if (lua_isnumber(L, -1)) { + /* we got the pdu_len */ + pdu_len = wslua_togint(L, -1); + lua_pop(L, 1); + } else { + luaL_error(L,"Lua Error dissect_tcp_pdus: get_len_func did not return a Lua number of the PDU length"); + } + } + + } else { + luaL_error(L,"Lua Error in dissect_tcp_pdus: did not find the get_len_func dissector"); + } + + return pdu_len; +} + +static int +wslua_dissect_tcp_dissector(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, void *data) +{ + func_saver_t* fs = (func_saver_t*)data; + lua_State* L = fs->state; + int consumed_bytes = 0; + + lua_settop(L, 0); + lua_rawgeti(L, LUA_REGISTRYINDEX, fs->dissect_ref); + + if (lua_isfunction(L,1)) { + /* XXX: not sure if it's kosher to just use the tree as the item */ + TreeItem ti = create_TreeItem(tree, (proto_item*)tree); + + push_Tvb(L,tvb); + push_Pinfo(L,pinfo); + push_TreeItem(L,ti); + + if ( lua_pcall(L,3,1,0) ) { + luaL_error(L, "Lua Error dissect_tcp_pdus dissect_func: %s", lua_tostring(L,-1)); + } else { + /* if the Lua dissector reported the consumed bytes, pass it to our caller */ + if (lua_isnumber(L, -1)) { + /* we got the consumed bytes or the missing bytes as a negative number */ + consumed_bytes = wslua_togint(L, -1); + lua_pop(L, 1); + } + } + + } else { + luaL_error(L,"Lua Error dissect_tcp_pdus: did not find the dissect_func dissector"); + } + + return consumed_bytes; +} + + +WSLUA_FUNCTION wslua_dissect_tcp_pdus(lua_State* L) { + /* Make the TCP-layer invoke the given Lua dissection function for each + PDU in the TCP segment, of the length returned by the given get_len_func + function. + + This function is useful for protocols that run over TCP and that are + either a fixed length always, or have a minimum size and have a length + field encoded within that minimum portion that identifies their full + length. For such protocols, their protocol dissector function can invoke + this `dissect_tcp_pdus()` function to make it easier to handle dissecting + their protocol's messages (i.e., their protocol data unit (PDU)). This + function shouild not be used for protocols whose PDU length cannot be + determined from a fixed minimum portion, such as HTTP or Telnet. + + @since 1.99.2 + */ +#define WSLUA_ARG_dissect_tcp_pdus_TVB 1 /* The Tvb buffer to dissect PDUs from. */ +#define WSLUA_ARG_dissect_tcp_pdus_TREE 2 /* The Tvb buffer to dissect PDUs from. */ +#define WSLUA_ARG_dissect_tcp_pdus_MIN_HEADER_SIZE 3 /* The number of bytes + in the fixed-length part of the PDU. */ +#define WSLUA_ARG_dissect_tcp_pdus_GET_LEN_FUNC 4 /* A Lua function that will be + called for each PDU, to determine the full length of the + PDU. The called function will be given (1) the `Tvb` object + of the whole `Tvb` (possibly reassembled), (2) the `Pinfo` object, + and (3) an offset number of the index of the first byte + of the PDU (i.e., its first header byte). The Lua function + must return a Lua number of the full length of the PDU. */ +#define WSLUA_ARG_dissect_tcp_pdus_DISSECT_FUNC 5 /* A Lua function that will be + called for each PDU, to dissect the PDU. The called + function will be given (1) the `Tvb` object of the PDU's + `Tvb` (possibly reassembled), (2) the `Pinfo` object, + and (3) the `TreeItem` object. The Lua function must + return a Lua number of the number of bytes read/handled, + which would typically be the `Tvb:len()`.*/ +#define WSLUA_OPTARG_dissect_tcp_pdus_DESEGMENT 6 /* Whether to reassemble PDUs + crossing TCP segment boundaries or not. (default=true) */ + Tvb tvb = checkTvb(L,WSLUA_ARG_dissect_tcp_pdus_TVB); + TreeItem ti = checkTreeItem(L,WSLUA_ARG_dissect_tcp_pdus_TREE); + guint fixed_len = (guint)luaL_checkinteger(L,WSLUA_ARG_dissect_tcp_pdus_MIN_HEADER_SIZE); + gboolean proto_desegment = wslua_optbool(L, WSLUA_OPTARG_dissect_tcp_pdus_DESEGMENT, TRUE); + + if (!lua_pinfo) { + luaL_error(L,"dissect_tcp_pdus can only be invoked while in a dissect function"); + return 0; + } + + if (lua_isfunction(L,WSLUA_ARG_dissect_tcp_pdus_GET_LEN_FUNC) && + lua_isfunction(L,WSLUA_ARG_dissect_tcp_pdus_DISSECT_FUNC)) + { + /* save the Lua functions so that we can call them later */ + func_saver_t* fs = g_new(func_saver_t, 1); + + lua_settop(L, WSLUA_ARG_dissect_tcp_pdus_DISSECT_FUNC); + + fs->state = L; + /* the following pops the top function and sets a ref to it in the registry */ + fs->dissect_ref = luaL_ref(L, LUA_REGISTRYINDEX); + fs->get_len_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + g_ptr_array_add(outstanding_FuncSavers, fs); + + tcp_dissect_pdus(tvb->ws_tvb, lua_pinfo, ti->tree, proto_desegment, + fixed_len, wslua_dissect_tcp_get_pdu_len, + wslua_dissect_tcp_dissector, (void*)fs); + } else { + luaL_error(L,"The third and fourth arguments need to be Lua functions"); + } + return 0; +} + + WSLUA_CLASS_DEFINE(Dissector,NOP,NOP); /* A refererence to a dissector, used to call a dissector against a packet or a part of it. @@ -2188,6 +2359,7 @@ WSLUA_META Dissector_meta[] = { int Dissector_register(lua_State* L) { WSLUA_REGISTER_CLASS(Dissector); + outstanding_FuncSavers = g_ptr_array_new(); return 0; } diff --git a/epan/wslua/wslua_tree.c b/epan/wslua/wslua_tree.c index 6a90d41b9e..bd0bb14e14 100644 --- a/epan/wslua/wslua_tree.c +++ b/epan/wslua/wslua_tree.c @@ -44,6 +44,16 @@ TreeItem* push_TreeItem(lua_State*L, TreeItem t) { return pushTreeItem(L,t); } +TreeItem create_TreeItem(proto_tree* tree, proto_item* item) +{ + TreeItem tree_item = (TreeItem)g_malloc(sizeof(struct _wslua_treeitem)); + tree_item->tree = tree; + tree_item->item = item; + tree_item->expired = FALSE; + + return tree_item; +} + CLEAR_OUTSTANDING(TreeItem, expired, TRUE) WSLUA_CLASS_DEFINE(TreeItem,FAIL_ON_NULL_OR_EXPIRED("TreeItem"),NOP); @@ -254,10 +264,7 @@ WSLUA_METHOD TreeItem_add_packet_field(lua_State *L) { nargs--; } - tree_item = (TreeItem)g_malloc(sizeof(struct _wslua_treeitem)); - tree_item->item = item; - tree_item->tree = proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett); - tree_item->expired = FALSE; + tree_item = create_TreeItem(proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item); PUSH_TREEITEM(L,tree_item); @@ -414,10 +421,7 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) { lua_remove(L,1); } - tree_item = (TreeItem)g_malloc(sizeof(struct _wslua_treeitem)); - tree_item->item = item; - tree_item->tree = proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett); - tree_item->expired = FALSE; + tree_item = create_TreeItem(proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item); PUSH_TREEITEM(L,tree_item); |