From 3aff2f44ae7972a5f147228a601215532983d537 Mon Sep 17 00:00:00 2001 From: Dmitry Pankov Date: Mon, 1 Jul 2024 13:32:54 +0300 Subject: [PATCH 1/2] Wireshark 4.0+ support for tarantool 1.5 proto --- tarantool15.dissector.lua | 216 ++++++++++++++++++++++++-------------- 1 file changed, 135 insertions(+), 81 deletions(-) diff --git a/tarantool15.dissector.lua b/tarantool15.dissector.lua index 691814b..5e5cc0f 100644 --- a/tarantool15.dissector.lua +++ b/tarantool15.dissector.lua @@ -1,7 +1,30 @@ +-- A table of our default settings - these can be changed by changing +-- the preferences through the GUI or command-line; the Lua-side of that +-- preference handling is at the end of this script file +local default_settings = +{ + debug = true, + enabled = true, -- whether this dissector is enabled or not + port = 33013, -- default TCP port number +} + +local debug = function(...) end +local function resetDebugLevel() + if default_settings.debug then + debug = function(...) + print(table.concat({"Lua: ", ...}," ")) + end + else + debug = function(...) end + end +end +-- call it now +resetDebugLevel() + -- declare the protocol -tarantool_proto = Proto("tarantool","Tarantool") +local tarantool_proto = Proto("tarantool15", "Tarantool 1.5") -function leb128Unpack(buffer, offset) +local function leb128Unpack(buffer, offset) -- see http://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer debug('-- leb128Unpack --') local result = 0 @@ -29,9 +52,7 @@ function leb128Unpack(buffer, offset) return result, used end - - -function add_one_tuple(buffer, subtree, num) +local function add_one_tuple(buffer, subtree, num) debug('-- add_one_tuple --') --[[ ::= + @@ -42,9 +63,9 @@ function add_one_tuple(buffer, subtree, num) ]] local data_length = 4 -- for cardinality local cardinality = buffer(0,4):le_uint() - + local array = {} - + for i=1,cardinality do debug('offset:'.. data_length) local field_length, used = leb128Unpack(buffer, data_length) @@ -54,36 +75,33 @@ function add_one_tuple(buffer, subtree, num) ['length'] = field_length, ['title'] = "Data (length: " .. field_length .. ')' } - + data_length = data_length + field_length + used end - + local tree = subtree:add( tarantool_proto, buffer(0, data_length),"Tuple #" .. num .. " (cardinality: "..cardinality..')') for i,v in ipairs(array) do tree:add(buffer(v.start, v.length), v.title) end - + return data_length - end -function add_tuples(buffer, subtree, name, count) +local function add_tuples(buffer, subtree, name, count) -- local count = count_buffer(0,4):le_uint() local tuples = subtree:add( tarantool_proto, buffer(), "Tuples") - + -- tuples:add( count_buffer(0,4), "Count: " .. count ) - + local offset = 0 for i=1,count do offset = offset + add_one_tuple( buffer(offset), tuples, i ) end - end -function add_fqtuple(buffer, subtree, name, count) - +local function add_fqtuple(buffer, subtree, name, count) local tuples = subtree:add( tarantool_proto, buffer(), "fq_tuples (count: " .. count ..')' ) - + local offset = 0 for i=1,count do local size = buffer(0,4):le_uint() @@ -91,18 +109,16 @@ function add_fqtuple(buffer, subtree, name, count) offset = offset + add_one_tuple( buffer(offset + 4), tuples, i ) offset = offset + 4 end - end -function select_request_body(buffer, subtree) +local function select_request_body(buffer, subtree) --[[ ::= + ]] - local tree = subtree:add( tarantool_proto, buffer(),"Select body") - + local namespace_no = buffer(0,4):le_uint() local index_no = buffer(4, 4):le_uint() local offset = buffer(8, 4):le_uint() @@ -115,13 +131,12 @@ function select_request_body(buffer, subtree) tree:add( buffer(4, 4), "Index # " .. index_no ) tree:add( buffer(8, 4), "Offset # " .. offset ) tree:add( buffer(12,4), "Limit # " .. limit ) - + tree:add( buffer(16,4), "Tuples count: " .. count ) add_tuples(buffer(20, buffer:len() - 20), tree, 'tuple', count) - end -function requestName(reqid) +local function requestName(reqid) local requests = { [13] = "INSERT", [17] = "SELECT", @@ -136,12 +151,12 @@ end -function decodeErrorCode(buf) +local function decodeErrorCode(buf) local completion_status = buf(0,1):le_uint() local error_code = buf(1):le_uint() - + local result = "Code " .. completion_status - + if ( completion_status == 0 ) then return "0 (Ok)" elseif ( completion_status == 1 ) then -- try again @@ -150,108 +165,112 @@ function decodeErrorCode(buf) return "2 (Error)" else return completion_status .. " (Unknown error code) " .. ' code: ' .. error_code - end + end end -function insert_request_body(buffer, subtree) +local function insert_request_body(buffer, subtree) --[[ ::= ]] local tree = subtree:add( tarantool_proto, buffer(),"Insert body") - + local namespace_no = buffer(0,4):le_uint() local flags = buffer(4, 4):le_uint() tree:add( buffer(0, 4), "Namespace # " .. namespace_no ) tree:add( buffer(4, 4), "Flags # " .. flags ) - + add_one_tuple(buffer(8), tree, 0) - end -function update_request_body(buffer, subtree) +local function update_request_body(buffer, subtree) subtree:add( buffer,"Update data" ) end -function deletev13_request_body(buffer, subtree) +local function deletev13_request_body(buffer, subtree) --[[ ::= ]] local tree = subtree:add( tarantool_proto, buffer(),"Delete body (v1.3)") - + local namespace_no = buffer(0,4):le_uint() tree:add( buffer(0, 4), "Namespace # " .. namespace_no ) - + add_one_tuple(buffer(4), tree, 1) - end -function delete_request_body(buffer, subtree) + +local function delete_request_body(buffer, subtree) subtree:add( buffer,"Delete data" ) end -function call_request_body(buffer, subtree) + +local function call_request_body(buffer, subtree) --[[ ::= ]] local tree = subtree:add( tarantool_proto, buffer,"Call data" ) - + local flags = buffer(0,4):le_uint() tree:add( buffer(0, 4), "Namespace # " .. flags ) - + local field_length, used = leb128Unpack(buffer, 4) local name = buffer(5, field_length):string() tree:add( buffer(5, field_length), "name " .. name ) - + add_one_tuple(buffer(4 + 1 + field_length), tree, 0) end - -function ping_request_body(buffer, subtree) +local function ping_request_body(buffer, subtree) subtree:add( buffer,"ping data" ) end -function unknown_request_body(buffer, subtree) + +local function unknown_request_body(buffer, subtree) subtree:add( buffer,"Unknown command data" ) end -function unknown_response_body(buffer, subtree) + +local function unknown_response_body(buffer, subtree) subtree:add( buffer,"Unknown response data" ) end -function insert_reponse_body(buffer, subtree) +local function insert_response_body(buffer, subtree) --[[ ::= | ]] local tree = subtree:add( tarantool_proto, buffer(),"Insert response") local count = buffer(0,4):le_uint() tree:add( buffer(0, 4), "Affected rows " .. count ) - + if ( buffer:len() > 4 ) then -- subtree:add( buffer(4),"Insert response data" ) add_fqtuple( buffer(4), subtree, "Select tuples", count) end end -function select_reponse_body(buffer, subtree) + +local function select_response_body(buffer, subtree) --[[ ::= * ]] local tree = subtree:add( tarantool_proto, buffer(),"Select response") local count = buffer(0,4):le_uint() tree:add( buffer(0, 4), "Count: " .. count ) - + if ( buffer:len() > 4 ) then add_fqtuple( buffer(4), subtree, "Select tuples", count) end end -function call_reponse_body(buffer, subtree) + +local function call_reponse_body(buffer, subtree) --[[ ::= ]] local tree = subtree:add( tarantool_proto, buffer(),"Call response") local count = buffer(0,4):le_uint() tree:add( buffer(0, 4), "Count: " .. count ) - + if ( buffer:len() > 4 ) then add_fqtuple( buffer(4), subtree, "Call tuples", count) end end -function requestfunction(reqid) + +local function requestfunction(reqid) local requests = { [13] = insert_request_body, [17] = select_request_body, @@ -266,13 +285,12 @@ function requestfunction(reqid) else return requests[reqid] end - end -function responsefunction(reqid) +local function responsefunction(reqid) local requests = { [13] = insert_response_body, - [17] = select_reponse_body, + [17] = select_response_body, [19] = unknown_response_body, [20] = unknown_response_body, -- old delete [21] = unknown_response_body, @@ -284,17 +302,16 @@ function responsefunction(reqid) else return requests[reqid] end - end -function readHeader(buffer, subtree) +local function readHeader(buffer, subtree) --[[
::= ]] local req_type = buffer(0,4):le_uint() local length = buffer(4,4):le_uint() local req_id = buffer(8,4):le_uint() - + local header = subtree:add( tarantool_proto, buffer(),"Header") header:add( buffer(0,4),"Request Type: " .. req_type .. ' (' .. requestName(req_type) .. ')' ) header:add( buffer(4,4),"Body length: " .. length ) @@ -303,34 +320,33 @@ function readHeader(buffer, subtree) return buffer(12, buffer:len() - 12) end -function request(buffer, subtree) +local function request(buffer, subtree) --[[ ::=
]] - local req_type = buffer(0,4):le_uint() - + buffer = readHeader(buffer, subtree) - + local requestfunction = requestfunction(req_type) requestfunction(buffer, subtree) end -function response(buffer, subtree) +local function response(buffer, subtree) --[[ ::=
{ ]] local req_type = buffer(0,4):le_uint() - + buffer = readHeader(buffer, subtree) if ( buffer:len() > 0 ) then - + local code = buffer(0,4):le_uint() if (code == 0) then subtree:add( buffer(0,4),"Return code: " .. decodeErrorCode(buffer(0,4)) ) - + local requestfunction = responsefunction(req_type) - + -- subtree:add( buffer(4),"Data" ) requestfunction(buffer(4), subtree) else @@ -343,15 +359,15 @@ end -- create a function to dissect it function tarantool_proto.dissector(buffer, pinfo, tree) pinfo.cols.protocol = "TARANTOOL" - + local body_length = buffer(4,4):le_uint() local request_length = body_length + 12 -- 12 - header length - - if (pinfo.src_port == 33013) then + + if (pinfo.src_port == default_settings.port) then -- answer, should have a response code -- request_length = request_length + 4 end - + -- debug('buffer: ' .. buffer:len()) -- debug('length: ' .. body_length) if (buffer:len() < request_length) then @@ -360,23 +376,61 @@ function tarantool_proto.dissector(buffer, pinfo, tree) pinfo.desegment_offset = 0 return 0 end - if (pinfo.src_port ~= 33013) then + if (pinfo.src_port ~= default_settings.port) then -- debug('parsing') local subtree = tree:add(tarantool_proto,buffer(),"Tarantool protocol data") - + -- subtree:add( buffer(0,4),"Request Type: " .. buffer(0,4):le_uint() .. ' ' .. requestName(buffer(0,4):le_uint()) ) request(buffer, subtree) else local subtree = tree:add(tarantool_proto,buffer(),"Tarantool protocol data (response)") response(buffer, subtree) end - + return request_length - end --- load the udp.port table -tcp_table = DissectorTable.get("tcp.port") --- register our protocol to handle udp port 7777 -tcp_table:add(33013,tarantool_proto) +-------------------------------------------------------------------------------- +-- We want to have our protocol dissection invoked for a specific TCP port, +-- so get the TCP dissector table and add our protocol to it. +local function enableDissector() + -- using DissectorTable:set() removes existing dissector(s), whereas the + -- DissectorTable:add() one adds ours before any existing ones, but + -- leaves the other ones alone, which is better + DissectorTable.get("tcp.port"):add(default_settings.port, tarantool_proto) +end +-- call it now, because we're enabled by default +enableDissector() + +local function disableDissector() + DissectorTable.get("tcp.port"):remove(default_settings.port, tarantool_proto) +end + +---------------------------------------- +-- register our preferences +tarantool_proto.prefs.enabled = Pref.bool("Dissector enabled", default_settings.enabled, + "Whether the tarantool dissector is enabled or not") + +tarantool_proto.prefs.debug = Pref.bool("Debug enabled", default_settings.debug, + "The debug printing is enabled or not") +---------------------------------------- +-- the function for handling preferences being changed +function tarantool_proto.prefs_changed() + debug("prefs_changed called") + + default_settings.debug = tarantool_proto.prefs.debug + resetDebugLevel() + + if default_settings.enabled ~= tarantool_proto.prefs.enabled then + default_settings.enabled = tarantool_proto.prefs.enabled + if default_settings.enabled then + enableDissector() + else + disableDissector() + end + -- have to reload the capture file for this type of change + reload() + end + +end From e22e1549868b4d3eaf8413f86fcebc56589344bf Mon Sep 17 00:00:00 2001 From: Dmitry Pankov Date: Tue, 9 Jun 2026 14:59:43 +0300 Subject: [PATCH 2/2] Wireshark 4.0+ support for both tarantools --- .../tarantool15.lua | 32 ++++- MessagePack.lua => tarantool2/MessagePack.lua | 0 .../tarantool2.lua | 129 ++++++++++-------- test.lua | 4 + 4 files changed, 106 insertions(+), 59 deletions(-) rename tarantool15.dissector.lua => tarantool15/tarantool15.lua (94%) rename MessagePack.lua => tarantool2/MessagePack.lua (100%) rename tarantool.dissector.lua => tarantool2/tarantool2.lua (83%) diff --git a/tarantool15.dissector.lua b/tarantool15/tarantool15.lua similarity index 94% rename from tarantool15.dissector.lua rename to tarantool15/tarantool15.lua index 5e5cc0f..835da29 100644 --- a/tarantool15.dissector.lua +++ b/tarantool15/tarantool15.lua @@ -3,7 +3,7 @@ -- preference handling is at the end of this script file local default_settings = { - debug = true, + debug = true, enabled = true, -- whether this dissector is enabled or not port = 33013, -- default TCP port number } @@ -411,6 +411,9 @@ end tarantool_proto.prefs.enabled = Pref.bool("Dissector enabled", default_settings.enabled, "Whether the tarantool dissector is enabled or not") +tarantool_proto.prefs.port = Pref.uint("Port number", default_settings.port, + "The TCP port number for Tarantool") + tarantool_proto.prefs.debug = Pref.bool("Debug enabled", default_settings.debug, "The debug printing is enabled or not") @@ -419,6 +422,8 @@ tarantool_proto.prefs.debug = Pref.bool("Debug enabled", default_settings. function tarantool_proto.prefs_changed() debug("prefs_changed called") + local need_reload = false + default_settings.debug = tarantool_proto.prefs.debug resetDebugLevel() @@ -429,8 +434,27 @@ function tarantool_proto.prefs_changed() else disableDissector() end - -- have to reload the capture file for this type of change - reload() + + need_reload = true end -end + if default_settings.port ~= tarantool_proto.prefs.port then + -- remove old one, if not 0 + if default_settings.port ~= 0 then + disableDissector() + end + -- set our new default + default_settings.port = tarantool_proto.prefs.port + -- add new one, if not 0 + if default_settings.port ~= 0 then + enableDissector() + end + + need_reload = true + end + + -- have to reload the capture file for this type of change + if need_reload then + reload() + end +end \ No newline at end of file diff --git a/MessagePack.lua b/tarantool2/MessagePack.lua similarity index 100% rename from MessagePack.lua rename to tarantool2/MessagePack.lua diff --git a/tarantool.dissector.lua b/tarantool2/tarantool2.lua similarity index 83% rename from tarantool.dissector.lua rename to tarantool2/tarantool2.lua index fd810f2..31a8974 100644 --- a/tarantool.dissector.lua +++ b/tarantool2/tarantool2.lua @@ -1,12 +1,6 @@ - -local msgpack = require 'MessagePack' +local msgpack = require('MessagePack') -- constants --- common -local GREETING_SIZE = 128 -local GREETING_SALT_OFFSET = 64 -local GREETING_SALT_SIZE = 44 - -- packet codes local OK = 0x00 local SELECT = 0x01 @@ -33,69 +27,43 @@ local FETCH_SNAPSHOT = 0x45 local REGISTER = 0x46 -- packet keys -local REQUEST_TYPE = 0x00 local TYPE = 0x00 local SYNC = 0x01 local REPLICA_ID = 0x02 local LSN = 0x03 -local TIMESTAMP = 0x04 -local SCHEMA_VERSION = 0x05 -local FLAGS = 0x09 local SPACE_ID = 0x10 local INDEX_ID = 0x11 local LIMIT = 0x12 local OFFSET = 0x13 local ITERATOR = 0x14 -local INDEX_BASE = 0x15 local KEY = 0x20 local TUPLE = 0x21 local FUNCTION_NAME = 0x22 local USER_NAME = 0x23 local INSTANCE_UUID = 0x24 -local CLUSTER_UUID = 0x25 local VCLOCK = 0x26 local EXPRESSION = 0x27 -local OPS = 0x28 -local BALLOT = 0x29 local DATA = 0x30 -local ERROR = 0x31 - -local BALLOT_IS_RO_CFG = 0x01 -local BALLOT_VCLOCK = 0x02 -local BALLOT_GC_VCLOCK = 0x03 -local BALLOT_IS_RO = 0x04 -local BALLOT_IS_ANON = 0x05 -local BALLOT_IS_BOOTED = 0x06 -local TUPLE_META = 0x2a -local OPTIONS = 0x2b -local ERROR_24 = 0x31 -local METADATA = 0x32 -local BIND_METADATA = 0x33 -local BIND_COUNT = 0x34 + local SQL_TEXT = 0x40 local SQL_BIND = 0x41 -local SQL_INFO = 0x42 local STMT_ID = 0x43 local ERROR = 0x52 -local FIELD_NAME = 0x00 -local FIELD_TYPE = 0x01 -local FIELD_COLL = 0x02 -local FIELD_IS_NULLABLE = 0x03 -local FIELD_IS_AUTOINCREMENT = 0x04 -local FIELD_SPAN = 0x05 --- declare the protocol -tarantool_proto = Proto("tarantool","Tarantool") ---[[ -local tnt_field_sync = ProtoField.new('tnt.sync', 'tnt.sync', ftypes.UINT32) - -tarantool_proto.fields = { - tnt_field_sync +-- A table of our default settings - these can be changed by changing +-- the preferences through the GUI or command-line; the Lua-side of that +-- preference handling is at the end of this script file +local default_settings = +{ + enabled = true, -- whether this dissector is enabled or not + port = 3303, -- default TCP port number } -]] + +-- declare the protocol +local tarantool_proto = Proto("tarantool2","Tarantool 2") -- extracts bytes from the buffer -function binary_string(buffer) +local function binary_string(buffer) local result = {} for i=0,buffer:len() - 1 do table.insert(result, string.char(buffer(i, 1):le_uint())) @@ -393,7 +361,7 @@ local function code_to_command(code) [CALL_16] = {name = 'call_16', decoder = parser_not_implemented}, -- Deprecated. [AUTH] = {name = 'auth', decoder = parse_auth}, [EVAL] = {name = 'eval', decoder = parse_eval}, - [UPSERT] = {name = 'upsert', decoder = parser_upsert}, + [UPSERT] = {name = 'upsert', decoder = parse_upsert}, [EXECUTE] = {name = 'execute', decoder = parse_execute}, [NOP] = {name = 'nop', decoder = parse_nop}, [PREPARE] = {name = 'prepare', decoder = parse_prepare}, @@ -450,7 +418,6 @@ function tarantool_proto.dissector(buffer, pinfo, tree) local request_length = packet_length + size_length if (buffer:len() < request_length) then - -- debug('reassemble required: ' .. (request_length - buffer:len()) ) pinfo.desegment_len = request_length - buffer:len() pinfo.desegment_offset = 0 return DESEGMENT_ONE_MORE_SEGMENT @@ -474,12 +441,6 @@ function tarantool_proto.dissector(buffer, pinfo, tree) decoder(body_data, body_buffer, subtree) pinfo.cols.info = command.name:gsub("^%l", string.upper) .. ' request. ' .. tostring(pinfo.cols.info) - --[[print(body_data, bytes_used) - for k,v in pairs(body_data) do - print(k,v) - end]] - -- subtree:add( buffer(0,4),"Request Type: " .. buffer(0,4):le_uint() .. ' ' .. requestName(buffer(0,4):le_uint()) ) - -- request(buffer, subtree) else local subtree = tree:add(tarantool_proto,buffer(),"Tarantool protocol data (response)") local header_descr = string.format('code: 0x%02x (%s), sync: 0x%04x', header_data[TYPE], command.name, header_data[SYNC]) @@ -492,5 +453,63 @@ function tarantool_proto.dissector(buffer, pinfo, tree) end -tcp_table = DissectorTable.get("tcp.port") -tcp_table:add(3301,tarantool_proto) +-------------------------------------------------------------------------------- +-- We want to have our protocol dissection invoked for a specific TCP port, +-- so get the TCP dissector table and add our protocol to it. +local function enableDissector() + -- using DissectorTable:set() removes existing dissector(s), whereas the + -- DissectorTable:add() one adds ours before any existing ones, but + -- leaves the other ones alone, which is better + DissectorTable.get("tcp.port"):add(default_settings.port, tarantool_proto) +end +-- call it now, because we're enabled by default +enableDissector() + +local function disableDissector() + DissectorTable.get("tcp.port"):remove(default_settings.port, tarantool_proto) +end + +---------------------------------------- +-- register our preferences +tarantool_proto.prefs.enabled = Pref.bool("Dissector enabled", default_settings.enabled, + "Whether the tarantool dissector is enabled or not") + +tarantool_proto.prefs.port = Pref.uint("Port number", default_settings.port, + "The TCP port number for Tarantool") + +---------------------------------------- +-- the function for handling preferences being changed +function tarantool_proto.prefs_changed() + local need_reload = false + + if default_settings.enabled ~= tarantool_proto.prefs.enabled then + default_settings.enabled = tarantool_proto.prefs.enabled + if default_settings.enabled then + enableDissector() + else + disableDissector() + end + + need_reload = true + end + + if default_settings.port ~= tarantool_proto.prefs.port then + -- remove old one, if not 0 + if default_settings.port ~= 0 then + disableDissector() + end + -- set our new default + default_settings.port = tarantool_proto.prefs.port + -- add new one, if not 0 + if default_settings.port ~= 0 then + enableDissector() + end + + need_reload = true + end + + -- have to reload the capture file for this type of change + if need_reload then + reload() + end +end diff --git a/test.lua b/test.lua index 1d034ff..811ee08 100644 --- a/test.lua +++ b/test.lua @@ -8,6 +8,10 @@ -- -- How to run: tarantool test.lua +if _TARANTOOL == nil then + return +end + local netbox = require('net.box') local popen = require('popen') local fiber = require('fiber')