aboutsummaryrefslogtreecommitdiffstats
path: root/epan/wslua/wslua_proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/wslua/wslua_proto.c')
-rw-r--r--epan/wslua/wslua_proto.c172
1 files changed, 172 insertions, 0 deletions
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;
}