# [LUA] How to get a field from a decoded protobuf to decode the next protobuf

I'm trying to create a protocol dissector in lua, but I can't find a way to get the data from a previously decoded protobuf to decode the next one within the same request.

I have a TCP protocol where a request contains the following data:

• total length -> 32bit int, total length of the message
• src -> 16bytes, identifier of sender
• dst -> 16bytes, identifier of destination
• message -> message (protobuf)

The operation message is always of the same message-type. This contains a type field that I have to read to know the type of the message message.

Is there a way to fetch the type from the first disector call so i can map this type to the correct version that I can then put in the pinfo.private["pb_msg_type"] field?

The lua code is based on the protobuf example.

    do
local protobuf_dissector = Dissector.get("protobuf")
local function create_protobuf_dissector(name, desc)
local proto = Proto(name, desc)
local f_len = ProtoField.uint32(name .. ".length", "Message length", base.DEC)
local f_src = ProtoField.bytes(name .. ".src", "Source", base.NONE)
local f_dst = ProtoField.bytes(name .. ".dst", "Destination", base.NONE)
local f_oplen = ProtoField.uint32(name .. ".oplength", "Operation length", base.DEC)

proto.fields = { f_len, f_src, f_dst, f_oplen }

proto.dissector = function(tvb, pinfo, tree)

-- Only process TCP packets
if pinfo.port_type == 2 then
local offset = 0
local remaining_len = tvb:len()
while remaining_len > 0 do
if remaining_len < 4 then
pinfo.desegment_offset = offset
pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
return -1
end

local data_len = tvb(offset, 4):uint()

if remaining_len - 4 < data_len then
-- data not enough
pinfo.desegment_offset = offset
pinfo.desegment_len = data_len - (remaining_len - 4)
return -1
end

pinfo.private["pb_msg_type"] = "message,GatewayOperation"
local op_len = tvb(offset + 36, 2):uint()
pcall(Dissector.call, protobuf_dissector, tvb(offset + 38, op_len):tvb(), pinfo, subtree)

-- todo: extract type from 1st message and apply mapping to define the type of the 2nd message

-- Process message
pinfo.private["pb_msg_type"] = "message,VersionConfirm"
pcall(Dissector.call, protobuf_dissector, tvb(offset + 38 + op_len):tvb(), pinfo, subtree)

offset = offset + 40 + data_len
remaining_len = remaining_len - 4 - data_len
end
end
pinfo.columns.protocol:set(name)
end

return proto
end

create_protobuf_dissector("Zehnder", "Zehnder Comfoconnect")
end

edit retag close merge delete

Sort by » oldest newest most voted

It sounds like what you need is to create your own DissectorTable. The dissectortable allows you to map your payload to the correct parser based on a parameter. This is the same behavior you are using to trigger your protobuf dissector from the tcp dissectortable:

In your case, sounds like in your top-level protobuf protocol lua file, you should create a new dissectortable in the lua file for the operation message.

DissectorTable.new('myoperation.type')

Then, create another Proto() for each of your messages. each of these message protocols will get the 'myoperation.type' dissectorTable and add a mapping using their 'type'. I do this in a .init() function so that you can put each protocol into its own file:

newmessage_proto = Proto('newmessage', 'this is the message used when type is 0x02')
newmessage_proto.fields = {newmessage_contents}

function newmessage_proto.init()
end

function newmessage_proto.dissector(tvb, pinfo, tree)
...do your dissection stuff for newmessage here..
end


Back in your top-level protobuf protocol file, inside of your .dissector function, you're going to consult the 'myoperation.type' dissectortable to find the appropriate sub-dissector based on the 'type'. I could not find in your example above exactly where you are extracting the 'type' field from, but

    -- todo: extract type
local type = 0x02
local dissector = DissectorTable.get('myoperation.type'):getDissector(type)

if dissector ~= nil then
-- Dissector was found, invoke subdissector with a new Tvb,
-- update this to pass the right buffer range to your sub-dissector.
dissector:call(buf(2):tvb(), pkt, tree)
else
-- fallback dissector that just shows the raw data.
data_dis:call(buf(2):tvb(), pkt, tree)
end


somewhat similar example which shows one protocol using the dissector table to determine how to decode its payload: https://www.wireshark.org/docs/wsdg_h...

I hope this helps. i don't have my development env in front of me to test this, and I'm no LUA expert, so please forgive the inevitable syntax errors.

more