From: Russ Combs Date: Tue, 11 Aug 2015 20:35:27 +0000 (-0400) Subject: Squashed commit of the following: X-Git-Tag: 3.0.0-233~880 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7d7ac4fc61719d2c5210502f6e32b5fa196e797e;p=thirdparty%2Fsnort3.git Squashed commit of the following: commit c5d47e48d14a6c447ff1e4a513341833dc6f29bf Author: Joel Cornett Date: Mon Aug 10 12:28:51 2015 -0400 added documentation to extending updated lua_iface added convenience functions for accessing RawBuffer data added reference tracking to interfaces exposed/added more methods to interfaces deleted RawData interface added lua_ref refactored Lua::Arg -> Lua::Args --- diff --git a/doc/extending.txt b/doc/extending.txt index fac4165d1..0f6f2cc75 100644 --- a/doc/extending.txt +++ b/doc/extending.txt @@ -276,6 +276,10 @@ Action plugins specify a builtin action in the API which is used to determine verdict. (Conversely, builtin actions don't have an associated plugin function.) +=== Developers Guide + +Run doc/dev_guide.sh to generate /tmp/dev_guide.html, an annotated guide to +the source tree. === Piglet Test Harness @@ -289,27 +293,23 @@ Here is a minimal example of a piglet test script for the IPv4 Codec plugin: plugin = { type = "piglet", - version = 1 - } - - piglet = - { - name = "my_test_for_ipv4_codec", - type = "codec", - target = "ipv4", + name = "codec::ipv4", + use_defaults = true, test = function() - local raw_data = RawData.new(1024) + local daq_header = DAQHeader.new() + local raw_buffer = RawBuffer.new("some data") local codec_data = CodecData.new() local decode_data = DecodeData.new() - codec("decode", raw_data, codec_data, decode_data) - return true + return Codec.decode( + daq_header, + raw_buffer, + codec_data, + decode_data + ) end } -More example tests can be found in the piglet_scripts directory. Refer to these -examples for furthur usage of Lua wrappers to snort data structures (such as Packet). - To run snort in piglet mode, first build snort with the BUILD_PIGLET option turned on (pass the flag -DBUILD_PIGLET:BOOL=ON in cmake). @@ -322,9 +322,281 @@ Then, run the following command: The test runner will generate a check-like output, indicating the the results of each test script. +=== Piglet Lua API -=== Developers Guide +This section documents the API that piglet exposes to Lua. +Refer to the piglet directory in the source tree for examples of usage. -Run doc/dev_guide.sh to generate /tmp/dev_guide.html, an annotated guide to -the source tree. +Note: Because of the differences between the Lua and C\++ data model and type +system, not all parameters map directly to the parameters of the underlying +C\++ member functions. Every effort has been made to keep the mappings consist, +but there are still some differences. They are documented below. + +==== Plugin Instances + +For each test, piglet instantiates plugin specified in the ++name++ field of the +++plugin++ table. The virtual methods of the instance are exposed in a table +unique to each plugin type. The name of the table is the CamelCase name of the +plugin type. + +For example, codec plugins have a virtual method called ++decode++. This method +is called like this: + + Codec.decode(...) + +*Codec* + +* ++Codec.get_data_link_type() -> { int, int, ... }++ +* ++Codec.get_protocol_ids() -> { int, int, ... }++ +* ++Codec.decode(DAQHeader, CodecData, DecodeData) -> bool++ +* ++Codec.log(RawBuffer, uint[lyr_len])++ +* ++Codec.encode(RawBuffer, EncState, Buffer) -> bool++ +* ++Codec.update(uint[flags_hi], uint[flags_lo], RawBuffer, uint[lyr_len] -> int++ +* ++Codec.format(bool[reverse], RawBuffer, DecodeData)++ + +Differences: + +* In ++Codec.update()++, the ++(uint64_t) flags++ parameter has been split into +++flags_hi++ and ++flags_lo++ + +*Inspector* + +* ++Inspector.configure()++ +* ++Inspector.tinit()++ +* ++Inspector.tterm()++ +* ++Inspector.likes(Packet)++ +* ++Inspector.eval(Packet)++ +* ++Inspector.clear(Packet)++ +* ++Inspector.get_buf_from_key(string[key], Packet, RawBuffer) -> bool++ +* ++Inspector.get_buf_from_id(uint[id], Packet, RawBuffer) -> bool++ +* ++Inspector.get_buf_from_type(uint[type], Packet, RawBuffer) -> bool++ +* ++Inspector.get_splitter(bool[to_server]) -> StreamSplitter++ + +Differences: +* In ++Inspector.configure()++, the ++SnortConfig*++ parameter is passed implicitly. +* the overloaded ++get_buf()++ member function has been split into three separate methods. + +*IpsOption* + +* ++IpsOption.hash() -> int++ +* ++IpsOption.is_relative() -> bool++ +* ++IpsOption.fp_research() -> bool++ +* ++IpsOption.get_cursor_type() -> int++ +* ++IpsOption.eval(Cursor, Packet) -> int++ +* ++IpsOption.action(Packet)++ + +*IpsAction* + +* ++IpsAction.exec(Packet)++ + +*Logger* + +* ++Logger.open()++ +* ++Logger.close()++ +* ++Logger.reset()++ +* ++Logger.alert(Packet, string[message], Event)++ +* ++Logger.log(Packet, string[message], Event)++ + +*SearchEngine* + +Currently, SearchEngine does not expose any methods. + +*SoRule* + +Currently, SoRule does not expose any methods. + +===== Interface Objects + +Many of the plugins take C\++ classes and structs as arguments. These objects +are exposed to the Lua API as Lua userdata. Exposed objects are instantiated +by calling the ++new++ method from each object's method table. + +For example, the DecodeData object can be instantiated and exposed to Lua +like this: + + local decode_data = DecodeData.new(...) + +Each object also exposes useful methods for getting and setting member variables, +and calling the C\++ methods contained in the the object. These methods can +be accessed using the ++:++ accessor syntax: + + decode_data:set({ sp = 80, dp = 3500 }) + +Since this is just syntactic sugar for passing the object as the first parameter +of the function ++DecodeData.set++, an equivalent form is: + + decode_data.set(decode_data, { sp = 80, dp = 3500 }) + +or even: + + DecodeData.set(decode_data, { sp = 80, dp = 3500 }) + +*Buffer* + +* ++Buffer.new(string[data]) -> Buffer++ +* ++Buffer.new(uint[length]) -> Buffer++ +* ++Buffer.new(RawBuffer) -> Buffer++ +* ++Buffer:allocate(uint[length]) -> bool++ +* ++Buffer:clear()++ + +*CodecData* + +* ++CodecData.new() -> Cursor++ +* ++CodecData.new(uint[next_prot_id]) -> Cursor++ +* ++CodecData.new(fields) -> Cursor++ + +* ++CodecData:get() -> fields++ +* ++CodecData:set(fields)++ + +++fields++ is a table with the following contents: + +* ++next_prot_id++ +* ++lyr_len++ +* ++invalid_bytes++ +* ++proto_bits++ +* ++codec_flags++ +* ++ip_layer_cnt++ +* ++ip6_extension_count++ +* ++curr_ip6_extension++ +* ++ip6_csum_proto++ + +*Cursor* + +* ++Cursor.new() -> Cursor++ +* ++Cursor.new(Packet) -> Cursor++ +* ++Cursor.new(string[data]) -> Cursor++ +* ++Cursor.new(RawBuffer) -> Cursor++ +* ++Cursor:reset()++ +* ++Cursor:reset(Packet)++ +* ++Cursor:reset(string[data])++ +* ++Cursor:reset(RawBuffer)++ + +*DAQHeader* + +* ++DAQHeader.new() -> DAQHeader++ +* ++DAQHeader.new(fields) -> DAQHeader++ +* ++DAQHeader:get() -> fields++ +* ++DAQHeader:set(fields)++ + +++fields++ is a table with the following contents: + +* ++caplen++ +* ++pktlen++ +* ++ingress_index++ +* ++egress_index++ +* ++ingress_group++ +* ++egress_group++ +* ++flags++ +* ++opaque++ + +*DecodeData* +* ++DecodeData.new() -> DecodeData++ +* ++DecodeData.new(fields) -> DecodeData++ +* ++DecodeData:reset()++ +* ++DecodeData:get() -> fields++ +* ++DecodeData:set(fields)++ +* ++DecodeData:set_ipv4_hdr(RawBuffer, uint[offset])++ + +++fields++ is a table with the following contents: + +* ++sp++ +* ++dp++ +* ++decode_flags++ +* ++type++ + +*EncState* + +* ++EncState.new() -> EncState++ +* ++EncState.new(uint[flags_lo]) -> EncState++ +* ++EncState.new(uint[flags_lo], uint[flags_hi]) -> EncState++ +* ++EncState.new(uint[flags_lo], uint[flags_hi], uint[next_proto]) -> EncState++ +* ++EncState.new(uint[flags_lo], uint[flags_hi], uint[next_proto], uint[ttl]) -> EncState++ +* ++EncState.new(uint[flags_lo], uint[flags_hi], uint[next_proto], uint[ttl], uint[dsize]) -> EncState++ + +*Event* + +* ++Event.new() -> Event++ +* ++Event.new(fields) -> Event++ +* ++Event:get() -> fields++ +* ++Event:set(fields)++ + +++fields++ is a table with the following contents: + +* ++event_id++ +* ++event_reference++ +* ++sig_info++ +** ++generator++ +** ++id++ +** ++rev++ +** ++class_id++ +** ++priority++ +** ++text_rule++ +** ++num_services++ + +*Flow* + +* ++Flow.new() -> Flow++ +* ++Flow:reset()++ + +*Packet* + +* ++Packet.new() -> Packet++ +* ++Packet.new(string[data]) -> Packet++ +* ++Packet.new(uint[size]) -> Packet++ +* ++Packet.new(fields) -> Packet++ +* ++Packet.new(RawBuffer) -> Packet++ +* ++Packet.new(DAQHeader) -> Packet++ +* ++Packet:set_decode_data(DecodeData)++ +* ++Packet:set_data(uint[offset], uint[length])++ +* ++Packet:set_flow(Flow)++ +* ++Packet:get() -> fields++ +* ++Packet:set() ++ +* ++Packet:set(string[data]) ++ +* ++Packet:set(uint[size]) ++ +* ++Packet:set(fields) ++ +* ++Packet:set(RawBuffer) ++ +* ++Packet:set(DAQHeader) ++ + +++fields++ is a table with the following contents: + +* ++packet_flags++ +* ++xtradata_mask++ +* ++proto_bits++ +* ++application_protocol_ordinal++ +* ++alt_dsize++ +* ++num_layers++ +* ++iplist_id++ +* ++user_policy_id++ +* ++ps_proto++ + +Note: ++Packet.new()++ and ++Packet:set()++ accept multiple arguments of the +types described above in any order + +*RawBuffer* + +* ++RawBuffer.new() -> RawBuffer++ +* ++RawBuffer.new(uint[size]) -> RawBuffer++ +* ++RawBuffer.new(string[data]) -> RawBuffer++ +* ++RawBuffer:size() -> int++ +* ++RawBuffer:resize(uint[size])++ +* ++RawBuffer:write(string[data])++ +* ++RawBuffer:write(string[data], uint[size])++ +* ++RawBuffer:read() -> string++ +* ++RawBuffer:read(uint[end]) -> string++ +* ++RawBuffer:read(uint[start], uint[end]) -> string++ + +Note: calling ++RawBuffer.new()++ with no arguments returns a RawBuffer of size 0 + +*StreamSplitter* + +* ++StreamSplitter:scan(Flow, RawBuffer) -> int, int++ +* ++StreamSplitter:scan(Flow, RawBuffer, uint[len]) -> int, int++ +* ++StreamSplitter:scan(Flow, RawBuffer, uint[len], uint[flags]) -> int, int++ +* ++StreamSplitter:reassemble(Flow, uint[total], uint[offset], RawBuffer) -> int, RawBuffer++ +* ++StreamSplitter:reassemble(Flow, uint[total], uint[offset], RawBuffer, uint[len]) -> int, RawBuffer++ +* ++StreamSplitter:reassemble(Flow, uint[total], uint[offset], RawBuffer, uint[len], uint[flags]) -> int, RawBuffer++ +* ++StreamSplitter:finish(Flow) -> bool++ + +Note: StreamSplitter does not have a ++new()++ method, it must be created by an inspector via +++Inspector.get_splitter()++ diff --git a/piglet/tests/instance/codec.lua b/piglet/tests/instance/codec.lua index 2b2b152dd..d33d5a309 100644 --- a/piglet/tests/instance/codec.lua +++ b/piglet/tests/instance/codec.lua @@ -28,13 +28,12 @@ tests = end, decode = function() - local rb = RawBuffer.new() + local daq = DAQHeader.new() + local rb = RawBuffer.new("foobar") local cd = CodecData.new() local dd = DecodeData.new() - local daq = DAQHeader.new() - local rd = RawData.new(rb, daq) - local rv = Codec.decode(rd, cd, dd) + local rv = Codec.decode(daq, rb, cd, dd) assert(not rv) end, @@ -59,11 +58,11 @@ tests = local rb = RawBuffer.new(64) -- FIXIT-H: checksum calculation is failing (temporarily set UPD_COOKED (0x1)) - local rv = Codec.update(1, rb) + local rv = Codec.update(0, 1, rb) assert(rv == 0) -- FIXIT-H: checksum calculation is failing (temporarily set UPD_COOKED (0x1)) - local rv = Codec.update(1, rb, 64) + local rv = Codec.update(0, 1, rb, 64) assert(rv == 0) end, diff --git a/piglet/tests/instance/inspector.lua b/piglet/tests/instance/inspector.lua index 7d37a6d05..cedef29b6 100644 --- a/piglet/tests/instance/inspector.lua +++ b/piglet/tests/instance/inspector.lua @@ -5,7 +5,9 @@ plugin = test = function() dofile(SCRIPT_DIR .. "/common.lua") return run_all(tests) - end + end, + -- FIXIT-L: Need this to keep Inspector.configure() happy + use_defaults = true } HEADER = [[ @@ -59,7 +61,7 @@ tests = local p, rb = get_packet() local ib = RawBuffer.new() - local rv = Inspector.get_buf_from_key(0, p, ib) + local rv = Inspector.get_buf_from_id(0, p, ib) assert(not rv) end, @@ -69,5 +71,22 @@ tests = spl = Inspector.get_splitter(true) assert(type(spl) == "userdata") + end, + + configure = function() + assert(Inspector.configure()) + end, + + tinit = function() + Inspector.tinit() + end, + + tterm = function() + Inspector.tterm() + end, + + likes = function() + local p = Packet.new() + assert(not Inspector.likes(p)) end } diff --git a/piglet/tests/instance/ips_option.lua b/piglet/tests/instance/ips_option.lua index 37ae2bcf0..a48ba5cb3 100644 --- a/piglet/tests/instance/ips_option.lua +++ b/piglet/tests/instance/ips_option.lua @@ -12,5 +12,33 @@ tests = { initialize = function() assert(IpsOption) + end, + + hash = function() + local rv = IpsOption.hash() + end, + + is_relative = function() assert(not IpsOption.is_relative()) end, + + fp_research = function() assert(not IpsOption.fp_research()) end, + + get_cursor_type = function() + local rv = IpsOption.get_cursor_type() + assert(rv == 1) + end, + + eval = function() + local rb = RawBuffer.new("foobar") + local cur = Cursor.new(rb) + local p = Packet.new(rb) + + local rv = IpsOption.eval(cur, p) + assert(rv) + end, + + action = function() + local rb = RawBuffer.new("foobar") + local p = Packet.new(rb) + IpsOption.action(p) end } diff --git a/piglet/tests/instance/logger.lua b/piglet/tests/instance/logger.lua index b17a5e2a7..58d2e61e2 100644 --- a/piglet/tests/instance/logger.lua +++ b/piglet/tests/instance/logger.lua @@ -2,6 +2,7 @@ plugin = { type = "piglet", name = "logger::alert_csv", + use_defaults = true, test = function() Logger.open() dofile(SCRIPT_DIR .. "/common.lua") diff --git a/piglet/tests/interface/buffer.lua b/piglet/tests/interface/buffer.lua index f663fee5b..b58dc4774 100644 --- a/piglet/tests/interface/buffer.lua +++ b/piglet/tests/interface/buffer.lua @@ -11,9 +11,40 @@ plugin = tests = { - initialization = function() - local rb = RawBuffer.new() + init_with_raw_buffer = function() + local rb = RawBuffer.new("abcdefghijklmnopqrstuvwxyz") local buf = Buffer.new(rb) assert(buf) + end, + + init_with_string = function() + local buf = Buffer.new("abcdefg") + assert(buf) + end, + + init_with_length = function() + local buf = Buffer.new(128) + assert(buf) + end, + + allocate = function() + local buf = Buffer.new(16) + assert(buf:allocate(10)) + assert(not buf:allocate(10)) + end, + + clear = function() + local buf = Buffer.new(16) + buf:allocate(16) + buf:clear() + assert(buf:allocate(10)) + end, + + to_string = function() + local buf = Buffer.new("abcdefgh") + buf:allocate(3) + local v = tostring(buf) + assert(#v == 3) + assert(v == "gh\0") end } diff --git a/piglet/tests/interface/cursor.lua b/piglet/tests/interface/cursor.lua index 6b1b762bd..ec978c4f1 100644 --- a/piglet/tests/interface/cursor.lua +++ b/piglet/tests/interface/cursor.lua @@ -11,10 +11,33 @@ plugin = tests = { - initialize = function() - local rb = RawBuffer.new() - local p = Packet.new(rb) - local cur = Cursor.new(p) + init_default = function() + local cur = Cursor.new() assert(cur) + end, + + init_from_string = function() + local cur = Cursor.new("abcdefgh") + assert(cur) + end, + + init_from_raw_buffer = function() + local cur = Cursor.new(RawBuffer.new("abcdefgh")) + assert(cur) + end, + + reset_default = function() + local cur = Cursor.new() + cur:reset() + end, + + reset_from_string = function() + local cur = Cursor.new() + cur:reset("abcdefgh") + end, + + reset_from_raw_buffer = function() + local cur = Cursor.new() + cur:reset(RawBuffer.new("abcdefgh")) end } diff --git a/piglet/tests/interface/enc_state.lua b/piglet/tests/interface/enc_state.lua index 97fb4ec69..54d7ef240 100644 --- a/piglet/tests/interface/enc_state.lua +++ b/piglet/tests/interface/enc_state.lua @@ -14,5 +14,8 @@ tests = initialize = function() local es = EncState.new() assert(es) + + es = EncState.new(0x80000000, 0xffffffff, 2, 24, 128) + assert(es) end } diff --git a/piglet/tests/interface/event.lua b/piglet/tests/interface/event.lua index 43e3dddc9..a04f226f0 100644 --- a/piglet/tests/interface/event.lua +++ b/piglet/tests/interface/event.lua @@ -45,11 +45,16 @@ SIGINFO_VALUES = tests = { - initialize = function() + init_default = function() local event = Event.new() assert(event) end, + init_with_table = function() + local event = Event.new(VALUES) + assert_table_eq("get()", VALUES, event:get()) + end, + get_and_set = function() local event = Event.new() assert_table_eq("get()", DEFAULT_VALUES, event:get()) diff --git a/piglet/tests/interface/packet.lua b/piglet/tests/interface/packet.lua index b520183a3..350a7ba6c 100644 --- a/piglet/tests/interface/packet.lua +++ b/piglet/tests/interface/packet.lua @@ -42,16 +42,35 @@ tests = assert(p) end, - initialize_with_data = function() + init_with_string = function() + local p = Packet.new("foobar") + assert(p) + end, + + init_with_size = function() + local p = Packet.new(128) + assert(p) + end, + + init_with_raw_buffer = function() local rb = RawBuffer.new() local p = Packet.new(rb) assert(p) end, - initialize_with_daq = function() - local rb = RawBuffer.new() + init_with_daq = function() local daq = DAQHeader.new() - local p = Packet.new(rb, daq) + local p = Packet.new(daq) + assert(p) + end, + + init_with_table = function() + local p = Packet.new(VALUES) + assert_table_eq("get()", VALUES, p:get()) + end, + + init_with_everything = function() + local p = Packet.new("foobar", DAQHeader.new(), { packet_flags = 4 }) assert(p) end, @@ -78,17 +97,5 @@ tests = assert_table_eq("get()", DEFAULT_VALUES, p:get()) p:set(VALUES) assert_table_eq("set()", VALUES, p:get()) - end, - - set_pkt = function() - local rb = RawBuffer.new() - local p = Packet.new() - p:set_pkt(rb) - end, - - set_daq = function() - local daq = DAQHeader.new() - local p = Packet.new() - p:set_daq(daq) end } diff --git a/piglet/tests/interface/raw_data.lua b/piglet/tests/interface/raw_data.lua deleted file mode 100644 index edbd54d48..000000000 --- a/piglet/tests/interface/raw_data.lua +++ /dev/null @@ -1,20 +0,0 @@ -plugin = -{ - type = "piglet", - name = "piglet::raw_data", - test = function() - -- Put the dofile here so that it doesn't get loaded twice - dofile(SCRIPT_DIR .. "/common.lua") - return run_all(tests) - end -} - -tests = -{ - initialize = function() - local rb = RawBuffer.new() - local daq = DAQHeader.new() - local rd = RawData.new(rb, daq) - assert(rd) - end -} diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt index 9f90ccfc4..8619ff5a6 100644 --- a/src/lua/CMakeLists.txt +++ b/src/lua/CMakeLists.txt @@ -1,7 +1,8 @@ add_library (lua STATIC lua.cc lua.h - lua_iface.cc + lua_ref.cc + lua_ref.h lua_iface.h lua_util.cc lua_util.h diff --git a/src/lua/Makefile.am b/src/lua/Makefile.am index 17ce1d6df..c3b090fa6 100644 --- a/src/lua/Makefile.am +++ b/src/lua/Makefile.am @@ -6,6 +6,7 @@ x_includedir = $(pkgincludedir)/lua x_include_HEADERS = \ lua.h \ +lua_ref.h \ lua_iface.h \ lua_table.h \ lua_arg.h \ @@ -15,7 +16,8 @@ lua_util.h liblua_a_SOURCES = \ lua.cc \ lua.h \ -lua_iface.cc \ +lua_ref.cc \ +lua_ref.h \ lua_iface.h \ lua_util.cc \ lua_util.h \ diff --git a/src/lua/lua_arg.h b/src/lua/lua_arg.h index 4de70a7bb..d92f2c4cb 100644 --- a/src/lua/lua_arg.h +++ b/src/lua/lua_arg.h @@ -22,145 +22,201 @@ #include +#include "lua_stack.h" + namespace Lua { -// FIXIT-M: generate better oob error messages -struct Arg +class Args { +public: + template + using ArgCallback = void (*)(lua_State*, int, T& ud); + + Args(lua_State* _L) : L { _L }, count { lua_gettop(L) } { } + +private: lua_State* L; - int count; - inline bool exists(int n) - { return !lua_isnone(L, n); } + struct ArgRef + { + public: + ArgRef(lua_State* _L, int ct, int i) : + L { _L }, count { ct }, index { i } { } - inline void check_type(int n, int type) - { luaL_checktype(L, n, type); } + // We treat nil as !exists + inline bool exists() + { return (index > 0) && (index <= count) && !lua_isnoneornil(L, index); } - // Types - inline bool is_type(int n, int type) - { return lua_type(L, n) == type; } + inline bool is_table() + { return exists() && lua_istable(L, index); } - inline bool is_number(int n) - { return is_type(n, LUA_TNUMBER); } + inline void check_table() + { luaL_checktype(L, index, LUA_TTABLE); } - inline bool is_string(int n) - { return is_type(n, LUA_TSTRING); } + template + inline void check_table(ArgCallback cb, T& ud) + { + check_table(); + cb(L, index, ud); + } - inline bool is_table(int n) - { return is_type(n, LUA_TTABLE); } + template + inline bool opt_table(ArgCallback cb, T& ud) + { + if ( exists() ) + { + check_table(cb, ud); + return true; + } - inline bool is_boolean(int n) - { return is_type(n, LUA_TBOOLEAN); } + return false; + } - // Table - inline void check_table(int n) - { check_type(n, LUA_TTABLE); } + inline bool is_function() + { return exists() && lua_isfunction(L, index); } - // Boolean - inline bool check_boolean(int n) - { - check_type(n, LUA_TBOOLEAN); - return lua_toboolean(L, n); - } + // FIXIT-L: We *may* need to insert checks for userdata, pointers, etc here - inline bool opt_boolean(int n, bool d = false) - { - if ( is_boolean(n) ) - return check_boolean(n); + inline bool is_int() + { return is(); } - return d; - } + inline int get_int() + { return get(); } - // String - inline const char* check_string(int n, size_t* len = nullptr) - { - check_type(n, LUA_TSTRING); - return lua_tolstring(L, n, len); - } + inline int check_int() + { return check("expected an integer"); } - inline const char* opt_string(int n, const char* d, size_t* len = nullptr) - { - if ( is_string(n) ) - return check_string(n, len); + inline int check_int(int max) + { + int v = check_int(); + return argcheck((v <= max), v, "Too big"); + } - return d; - } + inline int check_int(int min, int max) + { + int v = check_int(max); + return argcheck((v >= min), v, "Too small"); + } - // Integers - inline lua_Integer check_int(int n) - { - check_type(n, LUA_TNUMBER); - return lua_tointeger(L, n); - } + inline int opt_int(int d = 0) + { return ( exists() )? check_int() : d; } - inline lua_Integer check_int(int n, lua_Integer min, lua_Integer max) - { - auto v = check_int(n); - luaL_argcheck(L, ((v >= min) && (v <= max)), n, "oob"); - return v; - } + inline int opt_int(int d, int max) + { return ( exists() )? check_int(max) : d; } - inline lua_Integer opt_int(int n, lua_Integer d = 0) - { - if ( is_number(n) ) - return check_int(n); + inline int opt_int(int d, int min, int max) + { return ( exists() )? check_int(min, max) : d; } - return d; - } + inline bool is_size() + { return is(); } - inline lua_Integer opt_int( - int n, lua_Integer d, lua_Integer min, lua_Integer max) - { - auto v = opt_int(n, d); - luaL_argcheck(L, ((v >= min) && (v <= max)), n, "oob"); - return v; - } + inline unsigned get_size() + { return get(); } - inline unsigned check_size(int n) - { - auto v = check_int(n); - luaL_argcheck(L, (v >= 0), n, "oob"); - return v; - } + inline unsigned check_size() + { return check("expected an unsigned integer"); } - inline unsigned check_size(int n, unsigned max) - { - auto v = check_size(n); - luaL_argcheck(L, (v <= max), n, "oob"); - return v; - } + inline unsigned check_size(unsigned max) + { + unsigned v = check_size(); + return argcheck((v <= max), v, "too big"); + } - inline unsigned check_size(int n, unsigned min, unsigned max) - { - auto v = check_size(n, max); - luaL_argcheck(L, (v >= min), n, "oob"); - return v; - } + inline unsigned check_size(unsigned min, unsigned max) + { + unsigned v = check_size(max); + return argcheck((v >= min), v, "too small"); + } - inline unsigned opt_size(int n, unsigned d = 0) - { - if ( is_number(n) ) - return check_size(n); + inline unsigned opt_size(unsigned d = 0) + { return ( exists() ) ? check_size() : d; } - return d; - } + inline unsigned opt_size(unsigned d, unsigned max) + { return ( exists() ) ? check_size(max) : d; } - inline unsigned opt_size(int n, unsigned d, unsigned max) - { - auto v = opt_size(n, d); - luaL_argcheck(L, (v <= max), n, "oob"); - return v; - } + inline unsigned opt_size(unsigned d, unsigned min, unsigned max) + { return ( exists() ) ? check_size(min, max) : d; } + + inline bool is_string() + { return is(); } + + inline const char* get_string() + { return get(); } + + inline const char* check_string() + { return check("expected a string"); } + + inline const char* check_string(size_t& len) + { return check("expected a string", len); } + + inline const char* opt_string(const char* d = "") + { return ( exists() ) ? check_string() : d; } + + inline const char* opt_string(const char* d, size_t& len) + { return ( exists() ) ? check_string(len) : d; } + + inline bool is_bool() + { return is(); } + + inline bool get_bool() + { return get(); } + + inline bool check_bool() + { return check("expected a boolean"); } - inline unsigned opt_size(int n, unsigned d, unsigned min, unsigned max) + inline bool opt_bool(bool d = false) + { return ( exists() ) ? check_bool() : d; } + + private: + lua_State* L; + const int count; + + template + inline T argcheck(bool cond, T v, const char* msg) + { + luaL_argcheck(L, exists() && cond, index, msg); + return v; + } + + template + inline T check(const char* msg, Args&&... args) + { + T v; + return argcheck( + Stack::validate(L, index, v, std::forward(args)...), + v, msg + ); + } + + inline bool is(int type) + { return exists() && (type == lua_type(L, index)); } + + template + inline bool is() + { return is(Stack::type()); } + + template + inline T get() + { return Stack::get(L, index); } + + public: + const int index; + }; + +public: + const int count; + + ArgRef operator[](int i) { - auto v = opt_size(n, d, max); - luaL_argcheck(L, (v >= min), n, "oob"); - return v; - } + if ( i < 0 ) + i += count + 1; + + // If the index is invalid, mark it as such with 0 + if ( i < 0 ) + i = 0; - Arg(lua_State* state) : L(state) - { count = lua_gettop(L); } + return ArgRef(L, count, i); + } }; } #endif diff --git a/src/lua/lua_iface.cc b/src/lua/lua_iface.cc deleted file mode 100644 index 66abf7a63..000000000 --- a/src/lua/lua_iface.cc +++ /dev/null @@ -1,24 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- -// lua_iface.cc author Joel Cornett - -#include "lua_iface.h" - -#include - -namespace Lua { } diff --git a/src/lua/lua_iface.h b/src/lua/lua_iface.h index 0ed3cdbec..d372eb5c0 100644 --- a/src/lua/lua_iface.h +++ b/src/lua/lua_iface.h @@ -20,11 +20,10 @@ #ifndef LUA_IFACE_H #define LUA_IFACE_H -#include #include #include "lua.h" -#include "lua_stack.h" +#include "lua_ref.h" #include "lua_table.h" namespace Lua @@ -78,6 +77,8 @@ template struct TypeInterface { using type = T; + using AccessorCallback = void (*)(lua_State*, int, T&); + const char* name; const luaL_Reg* methods; const luaL_Reg* metamethods; @@ -88,12 +89,57 @@ struct TypeInterface T& get(lua_State* L, int arg = 1) const { return **regurgitate(L, arg); } + bool is(lua_State* L, int arg = 1) const + { + ManageStack ms(L, 1); + + if ( lua_type(L, arg) != LUA_TUSERDATA ) + return false; + + // Check the registry for metatable with name + lua_getfield(L, LUA_REGISTRYINDEX, name); + lua_getmetatable(L, arg); + + if ( !lua_rawequal(L, -1, -2) ) + return false; + + return true; + } + T** allocate(lua_State*) const; template T& create(lua_State*, Args&&...) const; void destroy(lua_State*, T** = nullptr) const; + + int default_tostring(lua_State* L) const + { + lua_pushfstring(L, "%s@0x%p", this->name, &this->get(L)); + return 1; + } + + int default_gc(lua_State* L) const + { + this->destroy(L); + return 0; + } + + int default_getter(lua_State* L, AccessorCallback acb) const + { + auto& self = this->get(L); + lua_newtable(L); + acb(L, lua_gettop(L), self); + return 1; + } + + int default_setter(lua_State* L, AccessorCallback acb) const + { + auto& self = this->get(L, 1); + luaL_checktype(L, 2, LUA_TTABLE); + acb(L, 2, self); + return 0; + } }; template @@ -126,6 +172,7 @@ void TypeInterface::destroy(lua_State* L, T** t) const if ( *t ) { + remove_refs(L, static_cast(*t)); delete *t; t = nullptr; } @@ -152,6 +199,16 @@ T& InstanceInterface::get(lua_State* L, int up) const return *static_cast(const_cast(lua_topointer(L, idx))); } +// ----------------------------------------------------------------------------- +// Library +// ----------------------------------------------------------------------------- + +struct Library +{ + const char* name; + const luaL_Reg* methods; +}; + // ----------------------------------------------------------------------------- // Installers // ----------------------------------------------------------------------------- @@ -178,5 +235,10 @@ void install(lua_State* L, const struct InstanceInterface& iface, T* instance int inst = lua_gettop(L); register_with_closure(L, iface.methods, table, inst); } + +static inline void install(lua_State* L, const struct Library& lib) +{ register_methods(L, lib.methods, lib.name); } + } + #endif diff --git a/src/lua/lua_ref.cc b/src/lua/lua_ref.cc new file mode 100644 index 000000000..b70bcfbf1 --- /dev/null +++ b/src/lua/lua_ref.cc @@ -0,0 +1,100 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// lua_ref.cc author Joel Cornett + +#include "lua_ref.h" + +#include + +#include "lua.h" + +// leave 2 items on the stack (key, ref table) +// uses 4 slots +static inline void create_registry_table(lua_State* L, void* p) +{ + // key = address of object + lua_pushlightuserdata(L, p); + // dup key + lua_pushvalue(L, -1); + // get: registry[key] + lua_gettable(L, LUA_REGISTRYINDEX); + + if ( lua_isnil(L, -1) ) + { + // remove nil + lua_pop(L, 1); + // ref = new ref table + lua_newtable(L); + // dup key + lua_pushvalue(L, -2); + // dup ref + lua_pushvalue(L, -2); + // set: registry[key] = ref + lua_settable(L, LUA_REGISTRYINDEX); + } +} + +// leaves 1 item on the stack (ref table or nil) +// uses 1 slot +static inline void lookup_registry_table(lua_State* L, void* p) +{ + lua_pushlightuserdata(L, p); + lua_gettable(L, LUA_REGISTRYINDEX); +} + +// leaves nothing extra on the stack +// uses 1 slot +static inline void add_entry(lua_State* L, const char* key, int index, int table) +{ + lua_pushvalue(L, index); + lua_setfield(L, table, key); +} + +// leaves nothing extra on the stack +// uses 1 slot +static inline void remove_entry(lua_State* L, const char* key, int table) +{ + lua_pushnil(L); + lua_setfield(L, table, key); +} + +namespace Lua +{ +void add_ref(lua_State* L, void* owner, const char* key, int ref_index) +{ + Lua::ManageStack ms(L, 4); + create_registry_table(L, owner); + add_entry(L, key, ref_index, lua_gettop(L)); +} + +void remove_ref(lua_State* L, void* owner, const char* key) +{ + Lua::ManageStack ms(L, 2); + lookup_registry_table(L, owner); + if ( !lua_isnil(L, -1) ) + remove_entry(L, key, lua_gettop(L)); +} + +void remove_refs(lua_State* L, void* owner) +{ + Lua::ManageStack ms(L, 2); + lua_pushlightuserdata(L, owner); + lua_pushnil(L); + lua_settable(L, LUA_REGISTRYINDEX); +} +} diff --git a/src/piglet_plugins/pp_raw_data_iface.h b/src/lua/lua_ref.h similarity index 74% rename from src/piglet_plugins/pp_raw_data_iface.h rename to src/lua/lua_ref.h index 7a9f4946c..78449d424 100644 --- a/src/piglet_plugins/pp_raw_data_iface.h +++ b/src/lua/lua_ref.h @@ -15,15 +15,19 @@ // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// pp_raw_data_iface.h author Joel Cornett +// lua_ref.h author Joel Cornett -#ifndef PP_RAW_DATA_IFACE_H -#define PP_RAW_DATA_IFACE_H +#ifndef LUA_REF_H +#define LUA_REF_H -#include "lua/lua_iface.h" +// Keep references to C objects in Lua to prevent premature garbage collection -struct RawData; - -extern const struct Lua::TypeInterface RawDataIface; +struct lua_State; +namespace Lua +{ +void add_ref(lua_State*, void*, const char*, int); +void remove_ref(lua_State*, void*, const char*); +void remove_refs(lua_State*, void*); +} #endif diff --git a/src/lua/lua_stack.h b/src/lua/lua_stack.h index a59a82419..e7d0b2a43 100644 --- a/src/lua/lua_stack.h +++ b/src/lua/lua_stack.h @@ -22,70 +22,171 @@ #include #include - #include -#include "lua_util.h" - namespace Lua { -template +template +static inline constexpr bool IsInteger() +{ return std::is_integral::value && !std::is_same::value; } + +template struct Stack {}; +// unsigned integer template -struct Stack::value>::type> +struct Stack()>::type, + typename std::enable_if::value>::type> { static inline void push(lua_State* L, const T& v) - { lua_pushnumber(L, v); } + { lua_pushinteger(L, v); } static inline T get(lua_State* L, int n) - { return lua_tonumber(L, n); } + { return lua_tointeger(L, n); } static inline constexpr int type() { return LUA_TNUMBER; } + + static inline bool validate(lua_State* L, int n, T& v) + { + if ( lua_type(L, n) != type() ) + return false; + + lua_Integer tmp = lua_tointeger(L, n); + if ( tmp < 0 ) + return false; + + v = tmp; + return true; + } + + static inline bool validate(lua_State* L, int n) + { + T v; + return validate(L, n, v); + } }; -template<> -struct Stack +// integer +template +struct Stack()>::type, + typename std::enable_if::value>::type> { - static inline void push(lua_State* L, const char* v) - { lua_pushstring(L, v); } + static inline void push(lua_State* L, const T& v) + { lua_pushinteger(L, v); } - static inline const char* get(lua_State* L, int n) - { return lua_tostring(L, n); } + static inline T get(lua_State* L, int n) + { return lua_tointeger(L, n); } static inline constexpr int type() - { return LUA_TSTRING; } + { return LUA_TNUMBER; } + + static inline bool validate(lua_State* L, int n, T& v) + { + if ( lua_type(L, n) != type() ) + return false; + + v = lua_tointeger(L, n); + return true; + } + + static inline bool validate(lua_State* L, int n) + { + T v; + return validate(L, n, v); + } }; -template<> -struct Stack +// default +template +struct Stack()>::type> { - static inline void push(lua_State* L, const std::string& v) - { lua_pushlstring(L, v.c_str(), v.size()); } + static inline void push(lua_State*, T); + static inline void push(lua_State*, T, size_t); + + static inline T get(lua_State*, int); + static inline T get(lua_State*, int, size_t&); - static inline std::string get(lua_State* L, int n) + static inline constexpr int type(); + + static inline bool validate(lua_State* L, int n, T& v) { - size_t len = 0; - const char* s = lua_tolstring(L, n, &len); - return std::string(s, len); + if ( lua_type(L, n) != type() ) + return false; + + v = get(L, n); + return true; } - static inline constexpr int type() - { return LUA_TSTRING; } + static inline bool validate(lua_State* L, int n) + { + T v; + return validate(L, n, v); + } + + static inline bool validate(lua_State*, int, T&, size_t&); }; +// const char* +template<> +inline void Stack::push(lua_State* L, const char* s) +{ lua_pushstring(L, s); } + +template<> +inline void Stack::push(lua_State* L, const char* s, size_t len) +{ lua_pushlstring(L, s, len); } + template<> -struct Stack +inline const char* Stack::get(lua_State* L, int n) +{ return lua_tostring(L, n); } + +template<> +inline const char* Stack::get(lua_State* L, int n, size_t& len) +{ return lua_tolstring(L, n, &len); } + +template<> +inline constexpr int Stack::type() +{ return LUA_TSTRING; } + +template<> +inline bool Stack::validate( + lua_State* L, int n, const char*& v, size_t& len) { - static inline void push(lua_State* L, const bool& v) - { lua_pushboolean(L, v); } + if ( lua_type(L, n) != type() ) + return false; - static inline bool get(lua_State* L, int n) - { return lua_toboolean(L, n); } + v = get(L, n, len); + return true; +} - static inline constexpr int type() - { return LUA_TBOOLEAN; } -}; +// string +template<> +inline void Stack::push(lua_State* L, std::string s) +{ lua_pushlstring(L, s.c_str(), s.length()); } + +template<> +inline std::string Stack::get(lua_State* L, int n) +{ + size_t len = 0; + const char* s = lua_tolstring(L, n, &len); + return std::string(s, len); +} + +template<> +inline constexpr int Stack::type() +{ return LUA_TSTRING; } + +// bool +template<> +inline void Stack::push(lua_State* L, bool v) +{ lua_pushboolean(L, v); } + +template<> +inline bool Stack::get(lua_State* L, int n) +{ return lua_toboolean(L, n); } + +template<> +inline constexpr int Stack::type() +{ return LUA_TBOOLEAN; } } #endif diff --git a/src/lua/lua_table.h b/src/lua/lua_table.h index 771c83042..fd4e689d2 100644 --- a/src/lua/lua_table.h +++ b/src/lua/lua_table.h @@ -75,6 +75,18 @@ struct Table return rv; } + template + inline bool get_default(const char* k, T& v, T d = 0) + { + if ( !get_field(k, v) ) + { + v = d; + return false; + } + + return true; + } + template inline bool raw_get_field(const char* k, T& v) { diff --git a/src/managers/script_manager.cc b/src/managers/script_manager.cc index 3312e0592..b7a221655 100644 --- a/src/managers/script_manager.cc +++ b/src/managers/script_manager.cc @@ -26,9 +26,9 @@ #include #include "ips_manager.h" +#include "plugin_manager.h" #include "lua/lua.h" #include "lua/lua_util.h" -#include "plugin_manager.h" #include "framework/ips_option.h" #include "framework/logger.h" #include "framework/lua_api.h" diff --git a/src/piglet/piglet_manager.cc b/src/piglet/piglet_manager.cc index c5c762aa6..f121b1efc 100644 --- a/src/piglet/piglet_manager.cc +++ b/src/piglet/piglet_manager.cc @@ -78,7 +78,8 @@ static const Api* find_piglet(PlugType key) return nullptr; } -static BasePlugin* instantiate(Lua::State& lua, PlugType key, std::string name) +static BasePlugin* instantiate( + Lua::State& lua, PlugType key, std::string name, bool use_defaults) { auto piglet_api = find_piglet(key); @@ -93,8 +94,7 @@ static BasePlugin* instantiate(Lua::State& lua, PlugType key, std::string name) } Module* m; - - if ( key == PT_IPS_OPTION ) + if ( key == PT_IPS_OPTION || use_defaults ) // FIXIT-M: this is just a workaround. // Need to be able to get parsed rule module m = ModuleManager::get_default_module(name.c_str(), snort_conf); @@ -124,7 +124,8 @@ void Manager::add_plugin(Api* api) { plugins[api->target] = api; } BasePlugin* Manager::instantiate( - Lua::State& lua, const string& target, string& type, string& name) + Lua::State& lua, const string& target, + string& type, string& name, bool use_defaults) { PlugType pt = PT_MAX; split_key(target, type, name); @@ -150,7 +151,7 @@ BasePlugin* Manager::instantiate( return nullptr; } - return ::Piglet::instantiate(lua, pt, name); + return ::Piglet::instantiate(lua, pt, name, use_defaults); } void Manager::destroy(BasePlugin* p) diff --git a/src/piglet/piglet_manager.h b/src/piglet/piglet_manager.h index 4f7ebad78..be34f76bf 100644 --- a/src/piglet/piglet_manager.h +++ b/src/piglet/piglet_manager.h @@ -47,7 +47,8 @@ public: static void add_plugin(Api*); static BasePlugin* instantiate( - Lua::State&, const std::string&, std::string&, std::string&); + Lua::State&, const std::string&, + std::string&, std::string&, bool = false); static void destroy(BasePlugin*); diff --git a/src/piglet/piglet_runner.cc b/src/piglet/piglet_runner.cc index a9d0eef75..f1a932a1b 100644 --- a/src/piglet/piglet_runner.cc +++ b/src/piglet/piglet_runner.cc @@ -51,6 +51,12 @@ static bool configure_test(lua_State* L, Test& t) { Lua::ManageStack ms(L); + if ( setup_globals(L, t) ) + { + t.set_error("couldn't setup globals"); + return true; + } + if ( load_chunk(L, t.chunk) ) { t.set_error("couldn't load test chunk"); @@ -75,8 +81,9 @@ static bool configure_test(lua_State* L, Test& t) Lua::Table table(L, -1); table.get_field("description", t.description); + table.get_field("use_defaults", t.use_defaults); - return setup_globals(L, t); + return false; } static bool run_test(lua_State* L, Test& t) @@ -125,7 +132,8 @@ void Runner::run(const struct Output& output, Test& t, unsigned i) return; } - auto p = Manager::instantiate(state, t.chunk.target, t.type, t.name); + auto p = Manager::instantiate( + state, t.chunk.target, t.type, t.name, t.use_defaults); // FIXIT-L: This injection is a hack so we can log the test header // with all the parsed information filled in diff --git a/src/piglet/piglet_utils.h b/src/piglet/piglet_utils.h index be575ef65..9f60638d2 100644 --- a/src/piglet/piglet_utils.h +++ b/src/piglet/piglet_utils.h @@ -88,6 +88,7 @@ struct Test std::string type; std::string name; std::string description; + bool use_defaults = false; std::vector messages; diff --git a/src/piglet_plugins/CMakeLists.txt b/src/piglet_plugins/CMakeLists.txt index 8a2fa33ef..51cf2375f 100644 --- a/src/piglet_plugins/CMakeLists.txt +++ b/src/piglet_plugins/CMakeLists.txt @@ -1,7 +1,6 @@ set ( PP_CODEC_DEPENDENCIES pp_codec_data_iface.cc - pp_raw_data_iface.cc pp_enc_state_iface.cc pp_buffer_iface.cc pp_event_iface.cc diff --git a/src/piglet_plugins/Makefile.am b/src/piglet_plugins/Makefile.am index be6ea00ec..e2653f2b1 100644 --- a/src/piglet_plugins/Makefile.am +++ b/src/piglet_plugins/Makefile.am @@ -7,7 +7,6 @@ piglet_plugins.h interface_list = \ pp_codec_data_iface.cc \ -pp_raw_data_iface.cc \ pp_enc_state_iface.cc \ pp_buffer_iface.cc \ pp_event_iface.cc \ diff --git a/src/piglet_plugins/dev_notes.txt b/src/piglet_plugins/dev_notes.txt index 0aa1e79a8..646137ef7 100644 --- a/src/piglet_plugins/dev_notes.txt +++ b/src/piglet_plugins/dev_notes.txt @@ -3,5 +3,5 @@ each Snort plugin type. Each pp_\*.cc source file is a Snort plugin proper. piglet_plugins_common contains utilities for working with the Lua C API and Lua interfaces for some useful Snort data structures (Packet, DecodeData). -There is also an interface called RawData. This is essentially a wrapper -around a vector. +There is also an interface called RawBuffer. This is essentially a wrapper +around a std::string. diff --git a/src/piglet_plugins/pp_buffer_iface.cc b/src/piglet_plugins/pp_buffer_iface.cc index 7fae7d565..058af769a 100644 --- a/src/piglet_plugins/pp_buffer_iface.cc +++ b/src/piglet_plugins/pp_buffer_iface.cc @@ -22,6 +22,8 @@ #include #include "framework/codec.h" +#include "lua/lua_arg.h" +#include "lua/lua_ref.h" #include "pp_raw_buffer_iface.h" static const luaL_Reg methods[] = @@ -30,19 +32,61 @@ static const luaL_Reg methods[] = "new", [](lua_State* L) { - // FIXIT-M: need a way to track refs to other - // objs in lua so the don't get gc'd too early - auto& rb = RawBufferIface.get(L); - BufferIface.create( - L, - const_cast( - reinterpret_cast(rb.data())), - rb.size() - ); + Lua::Args args(L); + + RawBuffer* rb; + size_t len; + int idx = 1; + + if ( args[1].is_string() ) + { + // Create a RawBuffer object to back the string + len = 0; + const char* s = args[1].check_string(len); + rb = &RawBufferIface.create(L, s, len); + idx = lua_gettop(L); + } + else if ( args[1].is_size() ) + { + len = args[1].check_size(); + // Create a RawBuffer object to back the string + rb = &RawBufferIface.create(L, len, '\0'); + idx = lua_gettop(L); + } + else + { + rb = &RawBufferIface.get(L, 1); + } + + auto& self = BufferIface.create(L, get_mutable_data(*rb), rb->size()); + // Save a reference to the RawBuffer + // FIXIT-M: Integrate this into the interface code so we don't + // have to do this explicitly + Lua::add_ref(L, &self, "data", idx); return 1; } }, + { + "allocate", + [](lua_State* L) + { + Lua::Args args(L); + auto& self = BufferIface.get(L, 1); + uint32_t len = args[2].check_size(); + bool result = self.allocate(len); + lua_pushboolean(L, result); + return 1; + } + }, + { + "clear", + [](lua_State* L) + { + BufferIface.get(L).clear(); + return 0; + } + }, { nullptr, nullptr } }; @@ -53,7 +97,9 @@ static const luaL_Reg metamethods[] = [](lua_State* L) { auto& self = BufferIface.get(L); - lua_pushfstring(L, "%s@%p", BufferIface.name, &self); + lua_pushlstring(L, reinterpret_cast(self.data()), + self.size()); + // lua_pushfstring(L, "%s@%p", BufferIface.name, &self); return 1; } diff --git a/src/piglet_plugins/pp_codec.cc b/src/piglet_plugins/pp_codec.cc index a93ef6287..5abc40796 100644 --- a/src/piglet_plugins/pp_codec.cc +++ b/src/piglet_plugins/pp_codec.cc @@ -31,7 +31,6 @@ #include "pp_decode_data_iface.h" #include "pp_enc_state_iface.h" #include "pp_raw_buffer_iface.h" -#include "pp_raw_data_iface.h" #include "pp_codec_iface.h" @@ -64,7 +63,6 @@ bool CodecPiglet::setup() install(L, RawBufferIface); install(L, DecodeDataIface); - install(L, RawDataIface); install(L, CodecDataIface); install(L, EncStateIface); install(L, BufferIface); diff --git a/src/piglet_plugins/pp_codec_data_iface.cc b/src/piglet_plugins/pp_codec_data_iface.cc index 4ca1fadc3..6f4f9c5fa 100644 --- a/src/piglet_plugins/pp_codec_data_iface.cc +++ b/src/piglet_plugins/pp_codec_data_iface.cc @@ -19,25 +19,41 @@ #include "pp_codec_data_iface.h" +#include #include #include "framework/codec.h" #include "lua/lua_table.h" #include "lua/lua_arg.h" -static void set_fields(lua_State* L, int tindex, CodecData& cd) +static void set_fields(lua_State* L, int tindex, CodecData& self) { Lua::Table table(L, tindex); - table.get_field("next_prot_id", cd.next_prot_id); - table.get_field("lyr_len", cd.lyr_len); - table.get_field("invalid_bytes", cd.invalid_bytes); - table.get_field("proto_bits", cd.proto_bits); - table.get_field("codec_flags", cd.codec_flags); - table.get_field("ip_layer_cnt", cd.ip_layer_cnt); - table.get_field("ip6_extension_count", cd.ip6_extension_count); - table.get_field("curr_ip6_extension", cd.curr_ip6_extension); - table.get_field("ip6_csum_proto", cd.ip6_csum_proto); + table.get_field("next_prot_id", self.next_prot_id); + table.get_field("lyr_len", self.lyr_len); + table.get_field("invalid_bytes", self.invalid_bytes); + table.get_field("proto_bits", self.proto_bits); + table.get_field("codec_flags", self.codec_flags); + table.get_field("ip_layer_cnt", self.ip_layer_cnt); + table.get_field("ip6_extension_count", self.ip6_extension_count); + table.get_field("curr_ip6_extension", self.curr_ip6_extension); + table.get_field("ip6_csum_proto", self.ip6_csum_proto); +} + +static void get_fields(lua_State* L, int tindex, CodecData& self) +{ + Lua::Table table(L, tindex); + + table.set_field("next_prot_id", self.next_prot_id); + table.set_field("lyr_len", self.lyr_len); + table.set_field("invalid_bytes", self.invalid_bytes); + table.set_field("proto_bits", self.proto_bits); + table.set_field("codec_flags", self.codec_flags); + table.set_field("ip_layer_cnt", self.ip_layer_cnt); + table.set_field("ip6_extension_count", self.ip6_extension_count); + table.set_field("curr_ip6_extension", self.curr_ip6_extension); + table.set_field("ip6_csum_proto", self.ip6_csum_proto); } static const luaL_Reg methods[] = @@ -46,17 +62,15 @@ static const luaL_Reg methods[] = "new", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = CodecDataIface.create(L, 0); + memset(&self, 0, sizeof(self)); - if ( arg.count ) - { - if ( arg.is_table(1) ) - set_fields(L, 1, self); - else - self.next_prot_id = arg.check_size(1); - } + if ( args[1].is_table() ) + args[1].check_table(set_fields, self); + else if ( args[1].is_size() ) + self.next_prot_id = args[1].check_size(); return 1; } @@ -64,38 +78,12 @@ static const luaL_Reg methods[] = { "get", [](lua_State* L) - { - auto& self = CodecDataIface.get(L); - lua_newtable(L); - - Lua::Table table(L, lua_gettop(L)); - - table.set_field("next_prot_id", self.next_prot_id); - table.set_field("lyr_len", self.lyr_len); - table.set_field("invalid_bytes", self.invalid_bytes); - table.set_field("proto_bits", self.proto_bits); - table.set_field("codec_flags", self.codec_flags); - table.set_field("ip_layer_cnt", self.ip_layer_cnt); - table.set_field("ip6_extension_count", self.ip6_extension_count); - table.set_field("curr_ip6_extension", self.curr_ip6_extension); - table.set_field("ip6_csum_proto", self.ip6_csum_proto); - - return 1; - } + { return CodecDataIface.default_getter(L, get_fields); } }, { "set", [](lua_State* L) - { - Lua::Arg arg(L); - - auto& self = CodecDataIface.get(L, 1); - - arg.check_table(2); - set_fields(L, 2, self); - - return 0; - } + { return CodecDataIface.default_setter(L, set_fields); } }, { nullptr, nullptr } }; @@ -105,20 +93,12 @@ static const luaL_Reg metamethods[] = { "__tostring", [](lua_State* L) - { - auto& self = CodecDataIface.get(L); - lua_pushfstring(L, "%s@%p", CodecDataIface.name, &self); - - return 1; - } + { return CodecDataIface.default_tostring(L); } }, { "__gc", [](lua_State* L) - { - CodecDataIface.destroy(L); - return 0; - } + { return CodecDataIface.default_gc(L); } }, { nullptr, nullptr } }; diff --git a/src/piglet_plugins/pp_codec_iface.cc b/src/piglet_plugins/pp_codec_iface.cc index fb63bc434..af91e8629 100644 --- a/src/piglet_plugins/pp_codec_iface.cc +++ b/src/piglet_plugins/pp_codec_iface.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include "framework/codec.h" @@ -31,14 +32,12 @@ #include "pp_buffer_iface.h" #include "pp_codec_data_iface.h" +#include "pp_daq_pkthdr_iface.h" #include "pp_decode_data_iface.h" #include "pp_enc_state_iface.h" #include "pp_raw_buffer_iface.h" -#include "pp_raw_data_iface.h" - -static std::vector data_link_types; -static std::vector protocol_ids; +// FIXIT-M: This should be its own object static const ip::IpApi ip_api {}; struct TextLogWrapper @@ -46,7 +45,10 @@ struct TextLogWrapper TextLog* text_log; TextLogWrapper(const char* name) - { text_log = TextLog_Init(name); } + { + text_log = TextLog_Init(name); + assert(text_log); + } ~TextLogWrapper() { @@ -91,13 +93,32 @@ static const luaL_Reg methods[] = "decode", [](lua_State* L) { - auto& rd = RawDataIface.get(L, 1); - auto& cd = CodecDataIface.get(L, 2); - auto& dd = DecodeDataIface.get(L, 3); + bool result; + + auto& daq = DAQHeaderIface.get(L, 1); + auto& cd = CodecDataIface.get(L, 3); + auto& dd = DecodeDataIface.get(L, 4); auto& self = CodecIface.get(L); - bool result = self.decode(rd, cd, dd); + if ( RawBufferIface.is(L, 2) ) + { + RawData rd(&daq, get_data(RawBufferIface.get(L, 2))); + result = self.decode(rd, cd, dd); + } + else + { + size_t len = 0; + RawData rd( + &daq, + reinterpret_cast( + luaL_checklstring(L, 2, &len) + ) + ); + + result = self.decode(rd, cd, dd); + } + lua_pushboolean(L, result); return 1; @@ -107,20 +128,15 @@ static const luaL_Reg methods[] = "log", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& rb = RawBufferIface.get(L, 1); - uint16_t lyr_len = arg.opt_size(2, rb.size(), rb.size()); + uint16_t lyr_len = args[2].opt_size(rb.size(), rb.size()); auto& self = CodecIface.get(L); TextLogWrapper tl_wrap("stdout"); - // FIXIT-L: Do we need to check for null tl_wrap.text_log? - self.log( - tl_wrap.text_log, - reinterpret_cast(rb.data()), - lyr_len - ); + self.log(tl_wrap.text_log, get_data(rb), lyr_len); return 0; } @@ -135,8 +151,7 @@ static const luaL_Reg methods[] = auto& self = CodecIface.get(L); - bool result = self.encode( - reinterpret_cast(rb.data()), rb.size(), es, b); + bool result = self.encode(get_data(rb), rb.size(), es, b); lua_pushboolean(L, result); @@ -147,23 +162,23 @@ static const luaL_Reg methods[] = "update", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); - // FIXIT-M: We can't represent all flags int lua_Integer type - uint64_t flags = arg.check_size(1); - auto& rb = RawBufferIface.get(L, 2); - uint16_t lyr_len = arg.opt_size(3, 0, rb.size()); + uint32_t flags_hi = args[1].check_size(); + uint32_t flags_lo = args[2].check_size(); + auto& rb = RawBufferIface.get(L, 3); + + // FIXIT-L: Args vs Iface is not orthogonal + uint16_t lyr_len = args[4].opt_size(0, rb.size()); auto& self = CodecIface.get(L); uint32_t updated_len = 0; - self.update( - ip_api, flags, - const_cast( - reinterpret_cast(rb.data())), - lyr_len, updated_len - ); + uint64_t flags = (static_cast(flags_hi) << 8) | flags_lo; + + self.update(ip_api, flags, get_mutable_data(rb), lyr_len, + updated_len); lua_pushinteger(L, updated_len); @@ -174,17 +189,15 @@ static const luaL_Reg methods[] = "format", [](lua_State* L) { - bool reverse = lua_toboolean(L, 1); + Lua::Args args(L); + + bool reverse = args[1].get_bool(); auto& rb = RawBufferIface.get(L, 2); auto& dd = DecodeDataIface.get(L, 3); auto& self = CodecIface.get(L); - self.format( - reverse, - const_cast( - reinterpret_cast(rb.data())), - dd - ); + + self.format(reverse, get_mutable_data(rb), dd); return 0; } diff --git a/src/piglet_plugins/pp_cursor_iface.cc b/src/piglet_plugins/pp_cursor_iface.cc index 32002bbcc..2f099fa1e 100644 --- a/src/piglet_plugins/pp_cursor_iface.cc +++ b/src/piglet_plugins/pp_cursor_iface.cc @@ -22,7 +22,31 @@ #include #include "framework/cursor.h" +#include "lua/lua_arg.h" +#include "lua/lua_ref.h" +#include "protocols/packet.h" #include "pp_packet_iface.h" +#include "pp_raw_buffer_iface.h" + +static void reset_from_packet( + lua_State* L, Cursor& self, Packet& p, int p_idx) +{ + self.reset(&p); + Lua::add_ref(L, &self, "data", p_idx); +} + +static void reset_from_raw_buffer( + lua_State* L, Cursor& self, RawBuffer& rb, int rb_idx) +{ + Packet p; + p.reset(); + + p.data = get_data(rb); + p.dsize = rb.size(); + + self.reset(&p); + Lua::add_ref(L, &self, "data", rb_idx); +} static const luaL_Reg methods[] = { @@ -30,12 +54,79 @@ static const luaL_Reg methods[] = "new", [](lua_State* L) { - auto& p = PacketIface.get(L); - CursorIface.create(L, &p); + Lua::Args args(L); + Packet p; + p.reset(); + + auto& self = CursorIface.create(L, &p); + + if ( args.count ) + { + if ( PacketIface.is(L, 1) ) + { + reset_from_packet(L, self, PacketIface.get(L, 1), 1); + } + else if ( args[1].is_string() ) + { + size_t len = 0; + const char* s = args[1].check_string(len); + auto& rb = RawBufferIface.create(L, s, len); + reset_from_raw_buffer(L, self, rb, lua_gettop(L)); + lua_pop(L, 1); + } + else + { + reset_from_raw_buffer(L, self, RawBufferIface.get(L, 1), 1); + } + } return 1; } }, + { + "reset", + [](lua_State* L) + { + Lua::Args args(L); + + auto& self = CursorIface.get(L, 1); + + if ( args.count > 1 ) + { + if ( PacketIface.is(L, 2) ) + { + auto& p = PacketIface.get(L, 2); + reset_from_packet(L, self, p, 2); + } + else + { + if ( args[2].is_string() ) + { + size_t len = 0; + const char* s = args[2].check_string(len); + auto& rb = RawBufferIface.create(L, s, len); + reset_from_raw_buffer(L, self, rb, lua_gettop(L)); + } + else + { + auto& rb = RawBufferIface.get(L, 2); + reset_from_raw_buffer(L, self, rb, 2); + } + } + } + else + { + Packet p; + + p.reset(); + self.reset(&p); + + Lua::remove_ref(L, &self, "data"); + } + + return 0; + } + }, { nullptr, nullptr } }; @@ -44,20 +135,12 @@ static const luaL_Reg metamethods[] = { "__tostring", [](lua_State* L) - { - auto& self = CursorIface.get(L); - lua_pushfstring(L, "%s@%p", CursorIface.name, &self); - - return 1; - } + { return CursorIface.default_tostring(L); } }, { "__gc", [](lua_State* L) - { - CursorIface.destroy(L); - return 0; - } + { return CursorIface.default_gc(L); } }, { nullptr, nullptr } }; diff --git a/src/piglet_plugins/pp_daq_pkthdr_iface.cc b/src/piglet_plugins/pp_daq_pkthdr_iface.cc index 53a659f2f..ecb12e897 100644 --- a/src/piglet_plugins/pp_daq_pkthdr_iface.cc +++ b/src/piglet_plugins/pp_daq_pkthdr_iface.cc @@ -15,7 +15,7 @@ // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// pp_daq_pkthdr_iface.cc author Joel Cornett +// pp_codec_data_iface.cc author Joel Cornett #include "pp_daq_pkthdr_iface.h" @@ -23,51 +23,71 @@ #include "config.h" #endif +#include #include -#include "lua/lua_table.h" - extern "C" { #include } -static void daq_header_set(lua_State* L, int tindex, struct _daq_pkthdr& daq) +#include "lua/lua_arg.h" +#include "lua/lua_table.h" + + +static void set_fields(lua_State* L, int tindex, struct _daq_pkthdr& self) { Lua::Table table(L, tindex); - table.get_field("caplen", daq.caplen); - table.get_field("pktlen", daq.pktlen); - table.get_field("ingress_index", daq.ingress_index); - table.get_field("egress_index", daq.egress_index); - table.get_field("ingress_group", daq.ingress_group); - table.get_field("egress_group", daq.egress_group); - table.get_field("flags", daq.flags); - table.get_field("opaque", daq.opaque); + table.get_field("caplen", self.caplen); + table.get_field("pktlen", self.pktlen); + table.get_field("ingress_index", self.ingress_index); + table.get_field("egress_index", self.egress_index); + table.get_field("ingress_group", self.ingress_group); + table.get_field("egress_group", self.egress_group); + table.get_field("flags", self.flags); + table.get_field("opaque", self.opaque); #ifdef HAVE_DAQ_ADDRESS_SPACE_ID #ifdef HAVE_DAQ_FLOW_ID - table.get_field("flow_id", daq.flow_id); + table.get_field("flow_id", self.flow_id); #endif - table.get_field("address_space_id", daq.address_space_id); + table.get_field("address_space_id", self.address_space_id); #endif // FIXIT-L: Do we want to be able to set the priv_ptr field? } +static void get_fields(lua_State* L, int tindex, struct _daq_pkthdr& self) +{ + Lua::Table table(L, tindex); + + table.set_field("caplen", self.caplen); + table.set_field("pktlen", self.pktlen); + table.set_field("ingress_index", self.ingress_index); + table.set_field("egress_index", self.egress_index); + table.set_field("ingress_group", self.ingress_group); + table.set_field("egress_group", self.egress_group); + table.set_field("flags", self.flags); + table.set_field("opaque", self.opaque); +#ifdef HAVE_DAQ_ADDRESS_SPACE_ID +#ifdef HAVE_DAQ_FLOW_ID + table.set_field("flow_id", self.flow_id); +#endif + table.set_field("address_space_id", self.address_space_id); +#endif +} + static const luaL_Reg methods[] = { { "new", [](lua_State* L) { + Lua::Args args(L); + auto& self = DAQHeaderIface.create(L); + memset(&self, 0, sizeof(self)); - // If we had an initializer argument, there - // will be two items on the stack now - if ( lua_gettop(L) > 1 ) - { - luaL_checktype(L, 1, LUA_TTABLE); - daq_header_set(L, 1, self); - } + args[1].opt_table(set_fields, self); return 1; } @@ -75,43 +95,12 @@ static const luaL_Reg methods[] = { "get", [](lua_State* L) - { - auto& self = DAQHeaderIface.get(L); - lua_newtable(L); - - Lua::Table table(L, lua_gettop(L)); - - table.set_field("caplen", self.caplen); - table.set_field("pktlen", self.pktlen); - table.set_field("ingress_index", self.ingress_index); - table.set_field("egress_index", self.egress_index); - table.set_field("ingress_group", self.ingress_group); - table.set_field("egress_group", self.egress_group); - table.set_field("flags", self.flags); - table.set_field("opaque", self.opaque); -#ifdef HAVE_DAQ_ADDRESS_SPACE_ID -#ifdef HAVE_DAQ_FLOW_ID - table.set_field("flow_id", self.flow_id); -#endif - table.set_field("address_space_id", self.address_space_id); -#endif - - // FIXIT-L: Do we want to be able to read the priv_ptr field? - - return 1; - } + { return DAQHeaderIface.default_getter(L, get_fields); } }, { "set", [](lua_State* L) - { - auto& self = DAQHeaderIface.get(L, 1); - luaL_checktype(L, 2, LUA_TTABLE); - - daq_header_set(L, 2, self); - - return 0; - } + { return DAQHeaderIface.default_setter(L, set_fields); } }, { nullptr, nullptr } }; @@ -121,20 +110,12 @@ static const luaL_Reg metamethods[] = { "__tostring", [](lua_State* L) - { - auto& self = DAQHeaderIface.get(L); - lua_pushfstring(L, "%s@%p", DAQHeaderIface.name, &self); - - return 1; - } + { return DAQHeaderIface.default_tostring(L); } }, { "__gc", [](lua_State* L) - { - DAQHeaderIface.destroy(L); - return 0; - } + { return DAQHeaderIface.default_gc(L); } }, { nullptr, nullptr } }; diff --git a/src/piglet_plugins/pp_decode_data_iface.cc b/src/piglet_plugins/pp_decode_data_iface.cc index a2e39fff5..9392191a7 100644 --- a/src/piglet_plugins/pp_decode_data_iface.cc +++ b/src/piglet_plugins/pp_decode_data_iface.cc @@ -19,26 +19,42 @@ #include "pp_decode_data_iface.h" +#include #include #include "framework/decode_data.h" #include "lua/lua_arg.h" #include "lua/lua_table.h" #include "protocols/ipv4.h" +// #include "protocols/tcp.h" +// #include "protocols/udp.h" +// #include "protocols/icmp4.h" #include "pp_raw_buffer_iface.h" -static void set_fields(lua_State* L, int tindex, DecodeData& dd) +// FIXIT-H: Add Internet Header objects +// FIXIT-H: Add Enum Interface +static void set_fields(lua_State* L, int tindex, DecodeData& self) { Lua::Table table(L, tindex); - table.get_field("sp", dd.sp); - table.get_field("dp", dd.dp); - table.get_field("decode_flags", dd.decode_flags); + table.get_field("sp", self.sp); + table.get_field("dp", self.dp); + table.get_field("decode_flags", self.decode_flags); uint8_t pkt_type = 0; table.get_field("type", pkt_type); - dd.type = static_cast(pkt_type); + self.type = static_cast(pkt_type); +} + +static void get_fields(lua_State* L, int tindex, DecodeData& self) +{ + Lua::Table table(L, tindex); + + table.set_field("sp", self.sp); + table.set_field("dp", self.dp); + table.set_field("decode_flags", self.decode_flags); + table.set_field("type", static_cast(self.type)); } static const luaL_Reg methods[] = @@ -47,15 +63,12 @@ static const luaL_Reg methods[] = "new", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = DecodeDataIface.create(L); + self.reset(); - if ( arg.count ) - { - arg.check_table(1); - set_fields(L, 1, self); - } + args[1].opt_table(set_fields, self); return 1; } @@ -64,55 +77,30 @@ static const luaL_Reg methods[] = "reset", [](lua_State* L) { - auto& self = DecodeDataIface.get(L); - self.reset(); - + DecodeDataIface.get(L).reset(); return 0; } }, { "set", [](lua_State* L) - { - Lua::Arg arg(L); - - auto& self = DecodeDataIface.get(L, 1); - - arg.check_table(2); - set_fields(L, 2, self); - - return 0; - } + { return DecodeDataIface.default_setter(L, set_fields); } }, { "get", [](lua_State* L) - { - auto& self = DecodeDataIface.get(L); - lua_newtable(L); - - Lua::Table table(L, lua_gettop(L)); - table.set_field("sp", self.sp); - table.set_field("dp", self.dp); - table.set_field("decode_flags", self.decode_flags); - table.set_field( - "type", - static_cast(self.type) - ); - - return 1; - } + { return DecodeDataIface.default_getter(L, get_fields); } }, // FIXIT-L: Need a more sophisticated interface to decode data ip_api { "set_ipv4_hdr", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = DecodeDataIface.get(L, 1); auto& rb = RawBufferIface.get(L, 2); - size_t offset = arg.opt_size(3, 0, rb.size()); + size_t offset = args[3].opt_size(0, rb.size()); // Need enough room for an IPv4 header if ( (rb.size() - offset) < sizeof(IP4Hdr) ) @@ -136,19 +124,12 @@ static const luaL_Reg metamethods[] = { "__tostring", [](lua_State* L) - { - auto& self = DecodeDataIface.get(L); - lua_pushfstring(L, "%s@%p", DecodeDataIface.name, &self); - return 1; - } + { return DecodeDataIface.default_tostring(L); } }, { "__gc", [](lua_State* L) - { - DecodeDataIface.destroy(L); - return 0; - } + { return DecodeDataIface.default_gc(L); } }, { nullptr, nullptr } }; diff --git a/src/piglet_plugins/pp_enc_state_iface.cc b/src/piglet_plugins/pp_enc_state_iface.cc index 102c1c2e2..777b3b518 100644 --- a/src/piglet_plugins/pp_enc_state_iface.cc +++ b/src/piglet_plugins/pp_enc_state_iface.cc @@ -22,20 +22,36 @@ #include #include "framework/codec.h" +#include "lua/lua_arg.h" #include "protocols/ip.h" +// FIXIT-H: This should also be its own object (copyable) static const class ip::IpApi ip_api {}; +static inline uint64_t get_encode_flag(uint32_t hi, uint32_t lo) +{ return (static_cast(hi) << 4) | lo; } + static const luaL_Reg methods[] = { { "new", [](lua_State* L) { - EncStateIface.create(L, ip_api, 0, 0, 0, 0); + Lua::Args args(L); + + uint32_t efl_hi = args[1].opt_size(); + uint32_t efl_lo = args[2].opt_size(); + uint8_t next_proto = args[3].opt_size(); + uint8_t ttl = args[4].opt_size(); + uint16_t dsize = args[5].opt_int(); + + EncStateIface.create(L, ip_api, get_encode_flag(efl_hi, efl_lo), + next_proto, ttl, dsize); + return 1; } }, + // FIXIT-L: Add get and set methods { nullptr, nullptr } }; @@ -44,20 +60,12 @@ static const luaL_Reg metamethods[] = { "__tostring", [](lua_State* L) - { - auto& self = EncStateIface.get(L); - lua_pushfstring(L, "%s@%p", EncStateIface.name, &self); - - return 1; - } + { return EncStateIface.default_tostring(L); } }, { "__gc", [](lua_State* L) - { - EncStateIface.destroy(L); - return 0; - } + { return EncStateIface.default_gc(L); } }, { nullptr, nullptr } }; diff --git a/src/piglet_plugins/pp_event_iface.cc b/src/piglet_plugins/pp_event_iface.cc index 7c15e864a..a0da62313 100644 --- a/src/piglet_plugins/pp_event_iface.cc +++ b/src/piglet_plugins/pp_event_iface.cc @@ -25,8 +25,11 @@ #include "detection/signature.h" #include "events/event.h" +#include "lua/lua_arg.h" #include "lua/lua_table.h" +#include "pp_raw_buffer_iface.h" +// FIXIT-H: Should be its own object static struct SigInfo* create_sig_info() { auto si = new SigInfo; @@ -34,15 +37,49 @@ static struct SigInfo* create_sig_info() return si; } +static void set_fields(lua_State* L, int tindex, Event& self) +{ + Lua::Table table(L, tindex); + + table.get_field("event_id", self.event_id); + table.get_field("event_reference", self.event_reference); + + const char* s = nullptr; + // FIXIT-L: Shouldn't need both conditions + if ( table.get_field("alt_msg", s) && s ) + { + self.alt_msg = RawBufferIface.create(L, s).c_str(); + Lua::add_ref(L, &self, "alt_msg", lua_gettop(L)); + lua_pop(L, 1); + } +} + +static void get_fields(lua_State* L, int tindex, Event& self) +{ + Lua::Table table(L, tindex); + + table.set_field("event_id", self.event_id); + table.set_field("event_reference", self.event_reference); + + if ( self.alt_msg ) + table.set_field("alt_msg", self.alt_msg); +} + static const luaL_Reg methods[] = { { "new", [](lua_State* L) { + Lua::Args args(L); + auto& self = EventIface.create(L); + // FIXIT-M: This should be a separate object + // (to make resource tracking more uniform) self.sig_info = create_sig_info(); + args[1].opt_table(set_fields, self); + return 1; } }, @@ -54,9 +91,7 @@ static const luaL_Reg methods[] = auto& self = EventIface.get(L); lua_newtable(L); - Lua::Table table(L, lua_gettop(L)); - table.set_field("event_id", self.event_id); - table.set_field("event_reference", self.event_reference); + get_fields(L, lua_gettop(L), self); auto si = self.sig_info; @@ -74,7 +109,7 @@ static const luaL_Reg methods[] = si_table.set_field("text_rule", si->text_rule); si_table.set_field("num_services", si->num_services); - table.set_field_from_stack("sig_info", si_table.index); + Lua::Table(L, 2).set_field_from_stack("sig_info", si_table.index); } return 1; @@ -107,8 +142,7 @@ static const luaL_Reg methods[] = si_table.get_field("num_services", si->num_services); } - table.get_field("event_id", self.event_id); - table.get_field("event_reference", self.event_reference); + set_fields(L, 2, self); return 0; } @@ -121,12 +155,7 @@ static const luaL_Reg metamethods[] = { "__tostring", [](lua_State* L) - { - auto& self = EventIface.get(L); - lua_pushfstring(L, "%s@%p", EventIface.name, &self); - - return 1; - } + { return EventIface.default_tostring(L); } }, { "__gc", diff --git a/src/piglet_plugins/pp_flow_iface.cc b/src/piglet_plugins/pp_flow_iface.cc index 187148a52..72de02905 100644 --- a/src/piglet_plugins/pp_flow_iface.cc +++ b/src/piglet_plugins/pp_flow_iface.cc @@ -31,9 +31,9 @@ static const luaL_Reg methods[] = "new", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); - PktType type = static_cast(arg.opt_size(1)); + PktType type = static_cast(args[1].opt_size()); FlowIface.create(L).init(type); diff --git a/src/piglet_plugins/pp_inspector_iface.cc b/src/piglet_plugins/pp_inspector_iface.cc index a4de784ba..280d340fe 100644 --- a/src/piglet_plugins/pp_inspector_iface.cc +++ b/src/piglet_plugins/pp_inspector_iface.cc @@ -26,6 +26,7 @@ #include "framework/inspector.h" #include "lua/lua_arg.h" +#include "main/snort_config.h" #include "pp_packet_iface.h" #include "pp_raw_buffer_iface.h" #include "pp_stream_splitter_iface.h" @@ -45,6 +46,44 @@ static inline bool get_buf( static const luaL_Reg methods[] = { + { + "configure", + [](lua_State* L) + { + auto& self = InspectorIface.get(L); + // FIXIT-L: Do we need an opaque SnortConfig interface? + bool result = self.configure(snort_conf); + lua_pushboolean(L, result); + return 1; + } + }, + { + "tinit", + [](lua_State* L) + { + InspectorIface.get(L).tinit(); + return 0; + }, + }, + { + "tterm", + [](lua_State* L) + { + InspectorIface.get(L).tterm(); + return 0; + } + }, + { + "likes", + [](lua_State* L) + { + auto& p = PacketIface.get(L, 1); + auto& self = InspectorIface.get(L); + bool result = self.likes(&p); + lua_pushboolean(L, result); + return 1; + } + }, { "eval", [](lua_State* L) @@ -69,21 +108,20 @@ static const luaL_Reg methods[] = return 0; } }, + // FIXIT-M: Add meta() method + // FIXIT-M: Add exec() method { "get_buf_from_key", [](lua_State* L) { - bool result; + Lua::Args args(L); auto& p = PacketIface.get(L, 2); auto& rb = RawBufferIface.get(L, 3); - auto& self = InspectorIface.get(L); - { - auto key = Lua::Stack::get(L, 1); - result = get_buf(self, key.c_str(), p, rb); - } + auto& self = InspectorIface.get(L); + bool result = get_buf(self, args[1].check_string(), p, rb); lua_pushboolean(L, result); return 1; @@ -93,16 +131,15 @@ static const luaL_Reg methods[] = "get_buf_from_id", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); - int id = arg.check_int(1); + int id = args[1].check_int(); auto& p = PacketIface.get(L, 2); auto& rb = RawBufferIface.get(L, 3); auto& self = InspectorIface.get(L); bool result = get_buf(self, id, p, rb); - lua_pushboolean(L, result); return 1; @@ -112,20 +149,15 @@ static const luaL_Reg methods[] = "get_buf_from_type", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); - int type = arg.check_int(1); + auto type = static_cast(args[1].check_int()); auto& p = PacketIface.get(L, 2); auto& rb = RawBufferIface.get(L, 3); auto& self = InspectorIface.get(L); - bool result = get_buf( - self, - static_cast(type), - p, rb - ); - + bool result = get_buf(self, type, p, rb); lua_pushboolean(L, result); return 1; @@ -135,9 +167,9 @@ static const luaL_Reg methods[] = "get_splitter", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); - bool to_server = arg.check_boolean(1); + bool to_server = args[1].check_bool(); auto& self = InspectorIface.get(L); auto** sp = StreamSplitterIface.allocate(L); diff --git a/src/piglet_plugins/pp_ips_option_iface.cc b/src/piglet_plugins/pp_ips_option_iface.cc index 5862a305d..4b282b452 100644 --- a/src/piglet_plugins/pp_ips_option_iface.cc +++ b/src/piglet_plugins/pp_ips_option_iface.cc @@ -22,11 +22,48 @@ #include #include "framework/ips_option.h" +#include "lua/lua_stack.h" #include "pp_packet_iface.h" #include "pp_cursor_iface.h" static const luaL_Reg methods[] = { + { + "hash", + [](lua_State* L) + { + uint32_t result = IpsOptionIface.get(L).hash(); + Lua::Stack::push(L, result); + return 1; + } + }, + { + "is_relative", + [](lua_State* L) + { + bool result = IpsOptionIface.get(L).is_relative(); + lua_pushboolean(L, result); + return 1; + } + }, + { + "fp_research", + [](lua_State* L) + { + bool result = IpsOptionIface.get(L).fp_research(); + lua_pushboolean(L, result); + return 1; + } + }, + { + "get_cursor_type", + [](lua_State* L) + { + CursorActionType cat = IpsOptionIface.get(L).get_cursor_type(); + Lua::Stack::push(L, static_cast(cat)); + return 1; + } + }, { "eval", [](lua_State* L) diff --git a/src/piglet_plugins/pp_logger_iface.cc b/src/piglet_plugins/pp_logger_iface.cc index 4c350b730..64c706332 100644 --- a/src/piglet_plugins/pp_logger_iface.cc +++ b/src/piglet_plugins/pp_logger_iface.cc @@ -33,8 +33,7 @@ static const luaL_Reg methods[] = "open", [](lua_State* L) { - auto& self = LoggerIface.get(L); - self.open(); + LoggerIface.get(L).open(); return 0; } }, @@ -42,8 +41,7 @@ static const luaL_Reg methods[] = "close", [](lua_State* L) { - auto& self = LoggerIface.get(L); - self.close(); + LoggerIface.get(L).close(); return 0; } }, @@ -51,8 +49,7 @@ static const luaL_Reg methods[] = "reset", [](lua_State* L) { - auto& self = LoggerIface.get(L); - self.reset(); + LoggerIface.get(L).reset(); return 0; } }, @@ -60,14 +57,14 @@ static const luaL_Reg methods[] = "alert", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& p = PacketIface.get(L, 1); - const char* msg = arg.check_string(2); auto& e = EventIface.get(L, 3); auto& self = LoggerIface.get(L); + const char* msg = args[2].check_string(); self.alert(&p, msg, &e); return 0; @@ -77,14 +74,14 @@ static const luaL_Reg methods[] = "log", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& p = PacketIface.get(L, 1); - const char* msg = arg.check_string(2); auto& e = EventIface.get(L, 3); auto& self = LoggerIface.get(L); + const char* msg = args[2].check_string(); self.log(&p, msg, &e); return 0; diff --git a/src/piglet_plugins/pp_packet_iface.cc b/src/piglet_plugins/pp_packet_iface.cc index 58094824e..c65d02094 100644 --- a/src/piglet_plugins/pp_packet_iface.cc +++ b/src/piglet_plugins/pp_packet_iface.cc @@ -19,6 +19,7 @@ #include "pp_packet_iface.h" +#include #include #include "lua/lua_arg.h" @@ -29,26 +30,99 @@ #include "pp_raw_buffer_iface.h" #include "pp_daq_pkthdr_iface.h" +static void set_fields(lua_State* L, int tindex, Packet& self) +{ + Lua::Table table(L, tindex); + + table.get_field("packet_flags", self.packet_flags); + table.get_field("xtradata_mask", self.xtradata_mask); + table.get_field("proto_bits", self.proto_bits); + table.get_field( + "application_protocol_ordinal", + self.application_protocol_ordinal + ); + + table.get_field("alt_dsize", self.alt_dsize); + table.get_field("num_layers", self.num_layers); + table.get_field("iplist_id", self.iplist_id); + table.get_field("user_policy_id", self.user_policy_id); + table.get_field("ps_proto", self.ps_proto); +} + +static void get_fields(lua_State* L, int tindex, Packet& self) +{ + Lua::Table table(L, tindex); + + table.set_field("packet_flags", self.packet_flags); + table.set_field("xtradata_mask", self.xtradata_mask); + table.set_field("proto_bits", self.proto_bits); + table.set_field( + "application_protocol_ordinal", + self.application_protocol_ordinal + ); + + table.set_field("alt_dsize", self.alt_dsize); + table.set_field("num_layers", self.num_layers); + table.set_field("iplist_id", self.iplist_id); + table.set_field("user_policy_id", self.user_policy_id); + table.set_field("ps_proto", self.ps_proto); +} + +static void set(lua_State* L, Packet& self, Lua::Args& args, int start) +{ + for ( int i = start; i <= args.count; i++ ) + { + if ( args[i].is_string() ) + { + size_t len = 0; + const char* s = args[i].check_string(len); + auto& rb = RawBufferIface.create(L, s, len); + self.pkt = get_data(rb); + Lua::add_ref(L, &self, "pkt", lua_gettop(L)); + lua_pop(L, 1); + } + else if ( args[i].is_size() ) + { + size_t sz = args[i].check_size(); + auto& rb = RawBufferIface.create(L, sz, '\0'); + self.pkt = get_data(rb); + Lua::add_ref(L, &self, "pkt", lua_gettop(L)); + lua_pop(L, 1); + } + else if ( args[i].is_table() ) + { + args[i].check_table(set_fields, self); + } + else if ( RawBufferIface.is(L, i) ) + { + self.pkt = get_data(RawBufferIface.get(L, i)); + Lua::add_ref(L, &self, "pkt", i); + } + else if ( DAQHeaderIface.is(L, i) ) + { + self.pkth = &DAQHeaderIface.get(L, i); + Lua::add_ref(L, &self, "pkth", i); + } + else + { + luaL_argerror(L, i, + "expected string or unsigned or table or RawBuffer or DAQHeader"); + } + } +} + static const luaL_Reg methods[] = { { "new", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = PacketIface.create(L); + self.reset(); - // (Optional) first argument is raw packet - if ( arg.count ) - { - auto& rb = RawBufferIface.get(L, 1); - self.pkt = reinterpret_cast(rb.data()); - } - - // (Optional) second argument is daq header - if ( arg.count > 1 ) - self.pkth = &DAQHeaderIface.get(L, 2); + set(L, self, args, 1); return 1; } @@ -57,11 +131,7 @@ static const luaL_Reg methods[] = "set_decode_data", [](lua_State* L) { - auto& self = PacketIface.get(L, 1); - auto& dd = DecodeDataIface.get(L, 2); - - self.ptrs = dd; - + PacketIface.get(L, 1).ptrs = DecodeDataIface.get(L, 2); return 0; } }, @@ -69,11 +139,11 @@ static const luaL_Reg methods[] = "set_data", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = PacketIface.get(L, 1); - size_t offset = arg.check_size(2); - size_t size = arg.check_size(3); + size_t offset = args[2].check_size(); + size_t size = args[3].check_size(); self.data = self.pkt + offset; self.dsize = size; @@ -89,6 +159,7 @@ static const luaL_Reg methods[] = auto& flow = FlowIface.get(L, 2); self.flow = &flow; + Lua::add_ref(L, &self, "flow", 2); return 0; } @@ -96,77 +167,17 @@ static const luaL_Reg methods[] = { "get", [](lua_State* L) - { - auto& self = PacketIface.get(L); - lua_newtable(L); - - Lua::Table table(L, lua_gettop(L)); - - table.set_field("packet_flags", self.packet_flags); - table.set_field("xtradata_mask", self.xtradata_mask); - table.set_field("proto_bits", self.proto_bits); - table.set_field( - "application_protocol_ordinal", - self.application_protocol_ordinal - ); - - table.set_field("alt_dsize", self.alt_dsize); - table.set_field("num_layers", self.num_layers); - table.set_field("iplist_id", self.iplist_id); - table.set_field("user_policy_id", self.user_policy_id); - table.set_field("ps_proto", self.ps_proto); - - return 1; - } + { return PacketIface.default_getter(L, get_fields); } }, { "set", [](lua_State* L) { - Lua::Arg arg(L); - - auto& self = PacketIface.get(L, 1); - - arg.check_table(2); + Lua::Args args(L); - Lua::Table table(L, 2); - table.get_field("packet_flags", self.packet_flags); - table.get_field("xtradata_mask", self.xtradata_mask); - table.get_field("proto_bits", self.proto_bits); - table.get_field( - "application_protocol_ordinal", - self.application_protocol_ordinal - ); - - table.get_field("alt_dsize", self.alt_dsize); - table.get_field("num_layers", self.num_layers); - table.get_field("iplist_id", self.iplist_id); - table.get_field("user_policy_id", self.user_policy_id); - table.get_field("ps_proto", self.ps_proto); - - return 0; - } - }, - { - "set_pkt", - [](lua_State* L) - { auto& self = PacketIface.get(L, 1); - auto& rb = RawBufferIface.get(L, 2); - self.pkt = reinterpret_cast(rb.data()); - - return 0; - } - }, - { - "set_daq", - [](lua_State* L) - { - auto& self = PacketIface.get(L, 1); - auto& daq = DAQHeaderIface.get(L, 2); - - self.pkth = &daq; + set(L, self, args, 2); return 0; } @@ -179,19 +190,12 @@ static const luaL_Reg metamethods[] = { "__tostring", [](lua_State* L) - { - auto& self = PacketIface.get(L); - lua_pushfstring(L, "%s@%p", PacketIface.name, &self); - return 1; - } + { return PacketIface.default_tostring(L); } }, { "__gc", [](lua_State* L) - { - PacketIface.destroy(L); - return 0; - } + { return PacketIface.default_gc(L); } }, { nullptr, nullptr } }; diff --git a/src/piglet_plugins/pp_raw_buffer_iface.cc b/src/piglet_plugins/pp_raw_buffer_iface.cc index 6790fa147..5829e5aef 100644 --- a/src/piglet_plugins/pp_raw_buffer_iface.cc +++ b/src/piglet_plugins/pp_raw_buffer_iface.cc @@ -30,11 +30,11 @@ static int init_from_string(lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); size_t len = 0; - const char* s = arg.check_string(1, &len); - size_t size = arg.opt_size(2, len); + const char* s = args[1].check_string(len); + size_t size = args[2].opt_size(len); // instantiate and adjust size if necessary RawBufferIface.create(L, s, len).resize(size, '\0'); @@ -44,9 +44,9 @@ static int init_from_string(lua_State* L) static int init_from_size(lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); - size_t size = arg.opt_size(1); + size_t size = args[1].opt_size(); RawBufferIface.create(L, size, '\0'); @@ -59,9 +59,9 @@ static const luaL_Reg methods[] = "new", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); - if ( arg.is_string(1) ) + if ( args[1].is_string() ) return init_from_string(L); return init_from_size(L); @@ -73,7 +73,6 @@ static const luaL_Reg methods[] = { auto& self = RawBufferIface.get(L); lua_pushinteger(L, self.size()); - return 1; } }, @@ -81,10 +80,10 @@ static const luaL_Reg methods[] = "resize", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = RawBufferIface.get(L, 1); - size_t new_size = arg.check_size(2); + size_t new_size = args[2].check_size(); self.resize(new_size, '\0'); @@ -95,13 +94,13 @@ static const luaL_Reg methods[] = "write", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = RawBufferIface.get(L, 1); size_t len = 0; - const char* s = arg.check_string(2, &len); - size_t offset = arg.opt_size(3); + const char* s = args[2].check_string(len); + size_t offset = args[3].opt_size(); size_t required = offset + len; if ( self.size() < required ) @@ -116,19 +115,19 @@ static const luaL_Reg methods[] = "read", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = RawBufferIface.get(L, 1); - if ( arg.count > 2 ) + if ( args.count > 2 ) { - size_t start = arg.check_size(2, self.size()); - size_t end = arg.check_size(3, start, self.size()); + size_t start = args[2].check_size(self.size()); + size_t end = args[3].check_size(start, self.size()); lua_pushlstring(L, self.data() + start, end - start); } else { - size_t end = arg.opt_size(2, self.size(), self.size()); + size_t end = args[2].opt_size(self.size(), self.size()); lua_pushlstring(L, self.data(), end); } @@ -145,17 +144,14 @@ static const luaL_Reg metamethods[] = [](lua_State* L) { auto& self = RawBufferIface.get(L); - lua_pushfstring(L, "%s@%p", RawBufferIface.name, &self); + lua_pushlstring(L, self.data(), self.size()); return 1; } }, { "__gc", [](lua_State* L) - { - RawBufferIface.destroy(L); - return 0; - } + { return RawBufferIface.default_gc(L); } }, { nullptr, nullptr } }; diff --git a/src/piglet_plugins/pp_raw_buffer_iface.h b/src/piglet_plugins/pp_raw_buffer_iface.h index aa94edb7d..7797ab40f 100644 --- a/src/piglet_plugins/pp_raw_buffer_iface.h +++ b/src/piglet_plugins/pp_raw_buffer_iface.h @@ -26,6 +26,12 @@ using RawBuffer = std::string; +static inline const uint8_t* get_data(RawBuffer& rb) +{ return reinterpret_cast(rb.data()); } + +static inline uint8_t* get_mutable_data(RawBuffer& rb) +{ return const_cast(get_data(rb)); } + extern const struct Lua::TypeInterface RawBufferIface; #endif diff --git a/src/piglet_plugins/pp_raw_data_iface.cc b/src/piglet_plugins/pp_raw_data_iface.cc deleted file mode 100644 index 06def1d12..000000000 --- a/src/piglet_plugins/pp_raw_data_iface.cc +++ /dev/null @@ -1,78 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- -// pp_raw_data_iface.cc author Joel Cornett - -#include "pp_raw_data_iface.h" - -#include - -extern "C" { -#include -} - -#include "framework/codec.h" -#include "pp_raw_buffer_iface.h" -#include "pp_daq_pkthdr_iface.h" - -static const luaL_Reg methods[] = -{ - { - "new", - [](lua_State* L) - { - auto& rb = RawBufferIface.get(L, 1); - auto& daq = DAQHeaderIface.get(L, 2); - - RawDataIface.create( - L, &daq, reinterpret_cast(rb.data())); - - return 1; - } - }, - { nullptr, nullptr } -}; - -static const luaL_Reg metamethods[] = -{ - { - "__tostring", - [](lua_State* L) - { - auto& self = RawDataIface.get(L); - lua_pushfstring(L, "%s@%p", RawDataIface.name, &self); - - return 1; - } - }, - { - "__gc", - [](lua_State* L) - { - RawDataIface.destroy(L); - return 0; - } - }, - { nullptr, nullptr } -}; - -const struct Lua::TypeInterface RawDataIface = -{ - "RawData", - methods, - metamethods -}; diff --git a/src/piglet_plugins/pp_stream_splitter_iface.cc b/src/piglet_plugins/pp_stream_splitter_iface.cc index 2eb20ab6e..562362088 100644 --- a/src/piglet_plugins/pp_stream_splitter_iface.cc +++ b/src/piglet_plugins/pp_stream_splitter_iface.cc @@ -38,19 +38,16 @@ static const luaL_Reg methods[] = "scan", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = StreamSplitterIface.get(L, 1); auto& flow = FlowIface.get(L, 2); auto& rb = RawBufferIface.get(L, 3); - uint32_t len = arg.opt_size(4, rb.size(), rb.size()); - uint32_t flags = arg.opt_size(5); + uint32_t len = args[4].opt_size(rb.size(), rb.size()); + uint32_t flags = args[5].opt_size(); uint32_t fp = 0; - auto status = self.scan( - &flow, reinterpret_cast(rb.data()), - len, flags, &fp - ); + auto status = self.scan(&flow, get_data(rb), len, flags, &fp); stack_push(L, status); Lua::Stack::push(L, fp); @@ -62,23 +59,20 @@ static const luaL_Reg methods[] = "reassemble", [](lua_State* L) { - Lua::Arg arg(L); + Lua::Args args(L); auto& self = StreamSplitterIface.get(L, 1); auto& flow = FlowIface.get(L, 2); - unsigned total = arg.check_size(3); - unsigned offset = arg.check_size(4); + unsigned total = args[3].check_size(); + unsigned offset = args[4].check_size(); auto& rb = RawBufferIface.get(L, 5); - unsigned len = arg.opt_size(6, rb.size()); - uint32_t flags = arg.opt_size(7); + unsigned len = args[6].opt_size(rb.size()); + uint32_t flags = args[7].opt_size(); unsigned copied = 0; - auto sb = self.reassemble( - &flow, total, offset, - reinterpret_cast(rb.data()), len, - flags, copied - ); + auto sb = self.reassemble(&flow, total, offset, get_data(rb), len, + flags, copied); Lua::Stack::push(L, copied); @@ -99,7 +93,6 @@ static const luaL_Reg methods[] = auto& flow = FlowIface.get(L, 2); bool result = self.finish(&flow); - lua_pushboolean(L, result); return 1; @@ -113,20 +106,12 @@ static const luaL_Reg metamethods[] = { "__tostring", [](lua_State* L) - { - auto& self = StreamSplitterIface.get(L); - lua_pushfstring(L, "%s@%p", StreamSplitterIface.name, &self); - - return 1; - } + { return StreamSplitterIface.default_tostring(L); } }, { "__gc", [](lua_State* L) - { - StreamSplitterIface.destroy(L); - return 0; - } + { return StreamSplitterIface.default_gc(L); } }, { nullptr, nullptr } }; diff --git a/src/piglet_plugins/pp_test.cc b/src/piglet_plugins/pp_test.cc index 9924b2993..165a2eba0 100644 --- a/src/piglet_plugins/pp_test.cc +++ b/src/piglet_plugins/pp_test.cc @@ -38,7 +38,6 @@ #include "pp_flow_iface.h" #include "pp_packet_iface.h" #include "pp_raw_buffer_iface.h" -#include "pp_raw_data_iface.h" class TestPiglet : public Piglet::BasePlugin { @@ -62,7 +61,6 @@ bool TestPiglet::setup() install(L, FlowIface); install(L, PacketIface); install(L, RawBufferIface); - install(L, RawDataIface); return false; } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 1d4fbcede..d68d76420 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -28,6 +28,8 @@ add_custom_command( add_library(unit_tests STATIC suite_decl.h suite_list.h + lua_stack_test.cc + lua_test_common.h sfip_test.cc sfrf_test.cc sfrt_test.cc diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 1411f5f77..7306907ab 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -6,6 +6,8 @@ suite_decl.h \ suite_list.h libtest_a_SOURCES = \ +lua_stack_test.cc \ +lua_test_common.h \ sfip_test.cc \ sfrf_test.cc \ sfrt_test.cc \ diff --git a/src/test/lua_stack_test.cc b/src/test/lua_stack_test.cc new file mode 100644 index 000000000..0ff511926 --- /dev/null +++ b/src/test/lua_stack_test.cc @@ -0,0 +1,411 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// lua_stack_test.cc author Joel Cornett + +#include +#include + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" +#endif + +#include + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#include "lua_test_common.h" +#include "lua/lua_stack.h" + +static lua_State* L = nullptr; + +static void LuaCleanup(void) +{ l_end_lua_state(L); } + +static void LuaFixture(void) +{ l_reset_lua_state(L); } + +START_TEST(test_signed) +{ + bool b; + int k; + + // Test get + lua_pushinteger(L, 3); + { + auto r = Lua::Stack::get(L, -1); + ck_assert_int_eq(r, 3); + } + lua_pop(L, 1); + + // Test push + int j = 4; + Lua::Stack::push(L, j); + { + lua_Integer l = lua_tointeger(L, -1); + ck_assert_int_eq(l, j); + } + lua_pop(L, 1); + + // Test validate, no output + lua_pushinteger(L, 1); + { + b = Lua::Stack::validate(L, -1); + ck_assert(b); + } + lua_pop(L, 1); + + // Test validate + k = 0; + lua_pushinteger(L, 5); + { + b = Lua::Stack::validate(L, -1, k); + ck_assert_int_eq(k, 5); + ck_assert(b); + } + lua_pop(L, 1); + + // Test validate false + k = 7; + lua_pushnil(L); + { + b = Lua::Stack::validate(L, -1, k); + ck_assert_int_eq(k, 7); + ck_assert(!b); + } + lua_pop(L, 1); +} +END_TEST + +START_TEST(test_unsigned) +{ + bool b; + unsigned short k; + + // Test get + lua_pushinteger(L, 3); + { + auto r = Lua::Stack::get(L, -1); + ck_assert_int_eq(r, 3); + } + lua_pop(L, 1); + + // Test push + unsigned short j = 4; + Lua::Stack::push(L, j); + { + lua_Integer l = lua_tointeger(L, -1); + ck_assert_int_eq(l, j); + } + lua_pop(L, 1); + + // Test validate, no output + lua_pushinteger(L, 1); + { + b = Lua::Stack::validate(L, -1); + ck_assert(b); + } + lua_pop(L, 1); + + // Test validate + k = 0; + lua_pushinteger(L, 5); + { + b = Lua::Stack::validate(L, -1, k); + ck_assert_int_eq(k, 5); + ck_assert(b); + } + lua_pop(L, 1); + + // Test validate false + k = 7; + lua_pushnil(L); + { + b = Lua::Stack::validate(L, -1, k); + ck_assert_int_eq(k, 7); + ck_assert(!b); + } + lua_pop(L, 1); + lua_pushinteger(L, -1); + { + b = Lua::Stack::validate(L, -1, k); + ck_assert_int_eq(k, 7); + ck_assert(!b); + } + lua_pop(L, 1); +} +END_TEST + +START_TEST(test_cstring) +{ + bool b; + const char* s; + size_t len; + + // Test type + ck_assert_int_eq(Lua::Stack::type(), LUA_TSTRING); + + // Test get + s = nullptr; + lua_pushstring(L, "foo"); + { + s = Lua::Stack::get(L, -1); + ck_assert_str_eq(s, "foo"); + } + lua_pop(L, 1); + + // Test get w/length + s = nullptr; + len = 0; + lua_pushlstring(L, "f\0b", 3); + { + s = Lua::Stack::get(L, -1, len); + ck_assert_uint_eq(len, 3); + l_assert_strn_eq(s, "f\0b", len); + } + lua_pop(L, 1); + + // Test push + s = "foo"; + Lua::Stack::push(L, s); + { + s = lua_tostring(L, -1); + ck_assert_str_eq(s, "foo"); + } + lua_pop(L, 1); + + len = 0; + s = "f\0o"; + Lua::Stack::push(L, s); + { + s = lua_tolstring(L, -1, &len); + ck_assert_str_eq(s, "f"); + ck_assert_uint_eq(len, 1); + } + lua_pop(L, 1); + + // Test push w/length + len = 0; + s = "f\0b"; + Lua::Stack::push(L, s, 3); + { + s = lua_tolstring(L, -1, &len); + ck_assert_uint_eq(len, 3); + l_assert_strn_eq(s, "f\0b", len); + } + lua_pop(L, 1); + + // Test validate, no output + lua_pushstring(L, "foo"); + { + b = Lua::Stack::validate(L, -1); + ck_assert(b); + } + lua_pop(L, 1); + + // Test validate + len = 0; + s = "foo"; + lua_pushstring(L, s); + { + s = nullptr; + b = Lua::Stack::validate(L, -1, s); + ck_assert(b); + ck_assert_str_eq(s, "foo"); + } + lua_pop(L, 1); + + // Test validate w/length + len = 0; + s = "f\0b"; + lua_pushlstring(L, s, 3); + { + s = nullptr; + b = Lua::Stack::validate(L, -1, s, len); + ck_assert(b); + l_assert_strn_eq(s, "f\0b", 3); + } + lua_pop(L, 1); + + // Test invalid + s = nullptr; + lua_pushnil(L); + { + b = Lua::Stack::validate(L, -1, s); + ck_assert(!s); + ck_assert(!b); + } + lua_pop(L, 1); + + s = nullptr; + lua_pushnil(L); + { + b = Lua::Stack::validate(L, -1, s, len); + ck_assert(!s); + ck_assert(!b); + } + lua_pop(L, 1); +} +END_TEST + +START_TEST(test_string) +{ + bool b; + const char* cs; + std::string s; + size_t len; + + // Test type + ck_assert_int_eq(Lua::Stack::type(), LUA_TSTRING); + + // Test get + lua_pushstring(L, "foo"); + { + s = Lua::Stack::get(L, -1); + ck_assert(s == "foo"); + } + lua_pop(L, 1); + + // Test get w/zeros + lua_pushlstring(L, "f\0b", 3); + { + s = Lua::Stack::get(L, -1); + ck_assert(s.length() == 3); + l_assert_strn_eq(s.c_str(), "f\0b", 3); + } + lua_pop(L, 1); + + // Test push + s = "foo"; + Lua::Stack::push(L, s); + { + cs = lua_tostring(L, -1); + ck_assert_str_eq(cs, "foo"); + } + lua_pop(L, 1); + + len = 0; + s.assign("f\0b", 3); + Lua::Stack::push(L, s); + { + cs = lua_tolstring(L, -1, &len); + ck_assert_uint_eq(len, 3); + l_assert_strn_eq(cs, "f\0b", len); + } + lua_pop(L, 1); + + // Test validate, no output + lua_pushstring(L, "foo"); + { + b = Lua::Stack::validate(L, -1); + ck_assert(b); + } + lua_pop(L, 1); + + // Test validate + lua_pushstring(L, "foo"); + { + b = Lua::Stack::validate(L, -1, s); + ck_assert(b); + ck_assert(s == "foo"); + } + lua_pop(L, 1); + + lua_pushlstring(L, "f\0o", 3); + { + b = Lua::Stack::validate(L, -1, s); + ck_assert(b); + ck_assert_uint_eq(s.length(), 3); + l_assert_strn_eq(s.c_str(), "f\0o", 3); + } + lua_pop(L, 1); + + // Test invalid + lua_pushnil(L); + { + b = Lua::Stack::validate(L, -1, s); + ck_assert(!b); + } + lua_pop(L, 1); +} +END_TEST + +START_TEST(test_bool) +{ + bool b, v; + + // Test get + lua_pushboolean(L, true); + { + v = Lua::Stack::get(L, -1); + ck_assert(v); + } + lua_pop(L, 1); + + // Test push + Lua::Stack::push(L, true); + { + v = lua_toboolean(L, -1); + ck_assert(v); + } + lua_pop(L, 1); + + // Test validate, no output + lua_pushboolean(L, true); + { + b = Lua::Stack::validate(L, -1); + ck_assert(b); + } + lua_pop(L, 1); + + // Test validate + lua_pushboolean(L, true); + { + b = Lua::Stack::validate(L, -1, v); + ck_assert(b); + ck_assert(v); + } + lua_pop(L, 1); + + // Test invalid + lua_pushnil(L); + { + b = Lua::Stack::validate(L, -1, v); + ck_assert(!b); + } + lua_pop(L, 1); +} +END_TEST + +Suite* TEST_SUITE_lua_stack(void) +{ + Suite* ps = suite_create("lua_stack"); + + TCase* tc = tcase_create("lua_stack"); + tcase_add_unchecked_fixture(tc, LuaFixture, LuaCleanup); + tcase_add_test(tc, test_signed); + tcase_add_test(tc, test_unsigned); + tcase_add_test(tc, test_cstring); + tcase_add_test(tc, test_string); + tcase_add_test(tc, test_bool); + suite_add_tcase(ps, tc); + + return ps; +} diff --git a/src/test/lua_test_common.h b/src/test/lua_test_common.h new file mode 100644 index 000000000..fb468b121 --- /dev/null +++ b/src/test/lua_test_common.h @@ -0,0 +1,42 @@ +#ifndef LUA_TEST_COMMON_H +#define LUA_TEST_COMMON_H + +#include +#include +#include + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" +#endif + +#include + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +static inline void l_assert_strn_eq(const char* a, const char* b, size_t n) +{ ck_assert(!strncmp(a, b, n)); } + +static inline void l_end_lua_state(lua_State*& L_ptr) +{ + if ( L_ptr ) + { + lua_close(L_ptr); + L_ptr = nullptr; + } +} + +static inline void l_reset_lua_state(lua_State*& L_ptr) +{ + l_end_lua_state(L_ptr); + L_ptr = luaL_newstate(); + luaL_openlibs(L_ptr); +} + +template +static inline constexpr size_t sizeofArray(T (&)[N]) +{ return N; } + +#endif