Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

[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
  • header length -> 16bit, length of header message
  • header -> header message (protobuf)
  • 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)
            local subtree = tree:add(proto, tvb())

            -- 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
                    -- head not enough
                    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

                subtree:add(f_len, tvb(offset, 4))
                subtree:add(f_src, tvb(offset + 4, 16))
                subtree:add(f_dst, tvb(offset + 20, 16))


                -- Process header
                pinfo.private["pb_msg_type"] = "message,GatewayOperation"
                subtree:add(f_oplen, tvb(offset + 36, 2))
                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

        DissectorTable.get("tcp.port"):add(0, proto)
        return proto
        end

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