1 | initial version |
From the Wireshark wiki - Protobuf#protocol-dependencies:
Protobuf content is normally dissected by Wireshark from some higher layer dissectors including gRPC or other UDP/TCP based dissectors
There are two TCP streams in the provided pcap file:
Add a Decode As...
entry for a Stream ID 1
TCP port (34727
):
# "Decode As" entries file for Wireshark 4.2.3. # # This file is regenerated each time "Decode As" preferences # are saved within Wireshark. Making manual changes should be safe, # however. decode_as_entry: tcp.port,34727,(none),HTTP2
The out of the box protobuf
decode:
Frame 46: 127 bytes on wire (1016 bits), 127 bytes captured (1016 bits) on interface lo, id 0 Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00) Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1 Transmission Control Protocol, Src Port: 34727, Dst Port: 50051, Seq: 602, Ack: 231, Len: 61 HyperText Transfer Protocol 2 GRPC Message: /export_data.streamDataOut/streamData, Request Protocol Buffers: /export_data.streamDataOut/streamData,request Message: export_data.streamDataArgs [Message Name: export_data.streamDataArgs] Field(1): Id = 1234 (int64) [Field Name: Id] [Field Type: int64 (3)] .000 1... = Field Number: 1 .... .000 = Wire Type: varint (0) Value: d209 Int64: 1234 Id: 1234 Field(2): data (bytes) [Field Name: data] [Field Type: bytes (12)] .001 0... = Field Number: 2 .... .010 = Wire Type: Length-delimited (2) Value Length: 42 Value: 0a0d6d6163446174612e70726f746f12190a1130303a30303a30303a30303a31323a464610eb86b5af06 data: (42 bytes) Data (42 bytes) Data: 0a0d6d6163446174612e70726f746f12190a1130303a30303a30303a30303a31323a464610eb86b5af06 Text: \n\rmacData.proto\x12\x19\n\x1100:00:00:00:12:FF\x10놵�\x06 [Length: 42]
Wireshark wiki - Protobuf field subdissectors:
A subdissector can register itself in "protobuf_field" dissector table for parsing the value of the field. The key of record in "protobuf_field" table is the full name of the field.
local protobuf_field_table = DissectorTable.get("protobuf_field") local png_dissector = Dissector.get("png") protobuf_field_table:add("tutorial.Person.portrait_image", png_dissector)
In their example, it's to decode a png
. Our goal is to decode an embedded protobuf
:
local protobuf_dissector = Dissector.get("protobuf") ... pinfo.private["pb_msg_type"] = "message,tutorial.AddressBook" pcall(Dissector.call, protobuf_dissector, tvb, pinfo, tree)
-- 240313_33954_nested_pb.lua -- "Am looking for working example for below case where data is serialized as bytes to another protobuf." -- https://ask.wireshark.org/question/33954/lua-example-for-protobuf-dissector-which-has-protobuf-encoded-within-protobuf/ -- Step 1 - document as you go. See header above and set_plugin_info(). local nested_pb_info = { version = "1.0.0", author = "Good Coder", description = "Decode nested protobufs", repository = "Floppy in top drawer" } set_plugin_info(nested_pb_info) do local protobuf_field_table = DissectorTable.get("protobuf_field") local protobuf_dissector = Dissector.get("protobuf") protobuf_message_name_f = Field.new("protobuf.message.name") encoded_pb_p = Proto("encoded_pb_dissector", "Encoded Protobuf") encoded_pb_p.dissector = function(tvb, pinfo, subtree) -- What is the message type for the nested protobufs local message_type = { ["export_data.streamDataArgs"] = "message,encoded_data.encodeDataInfo", ["encoded_data.encodeDataInfo"] = "message,mac_data.macDataInfo" } -- Prevent recursion by only calling on last message name in tree local message_name = { ["message,encoded_data.encodeDataInfo"] = "encoded_data.encodeDataInfo", ["message,mac_data.macDataInfo"] = "mac_data.macDataInfo" } finfo_messages = { protobuf_message_name_f() } if (#finfo_messages > 0) then local call_dissector -- First time we're called there will be no pb_msg_type if pinfo.private["pb_msg_type"] == nil then call_dissector = true end v_string = string.format("%s", finfo_messages[#finfo_messages]) -- Only call if last message is type we're asked to decode if v_string == message_name[pinfo.private["pb_msg_type"]] then call_dissector = true end if call_dissector == true then pinfo.private["pb_msg_type"] = message_type[v_string] local subsubtree = subtree:add(encoded_pb_p, tvb()) pcall(Dissector.call, protobuf_dissector, tvb, pinfo, subsubtree) end end end -- What fields are the encoded protobufs in protobuf_field_table:add("export_data.streamDataArgs.data", encoded_pb_p) protobuf_field_table:add("encoded_data.encodeDataInfo.val", encoded_pb_p) end
Frame 46: 127 bytes on wire (1016 bits), 127 bytes captured (1016 bits) on interface lo, id 0 Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00) Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1 Transmission Control Protocol, Src Port: 34727, Dst Port: 50051, Seq: 602, Ack: 231, Len: 61 HyperText Transfer Protocol 2 GRPC Message: /export_data.streamDataOut/streamData, Request Protocol Buffers: /export_data.streamDataOut/streamData,request Message: export_data.streamDataArgs [Message Name: export_data.streamDataArgs] Field(1): Id = 1234 (int64) [Field Name: Id] [Field Type: int64 (3)] .000 1... = Field Number: 1 .... .000 = Wire Type: varint (0) Value: d209 Int64: 1234 Id: 1234 Field(2): data (bytes) [Field Name: data] [Field Type: bytes (12)] .001 0... = Field Number: 2 .... .010 = Wire Type: Length-delimited (2) Value Length: 42 Value: 0a0d6d6163446174612e70726f746f12190a1130303a30303a30303a30303a31323a464610eb86b5af06 data: (42 bytes) Encoded Protobuf Protocol Buffers: encoded_data.encodeDataInfo Message: encoded_data.encodeDataInfo [Message Name: encoded_data.encodeDataInfo] Field(1): name = macData.proto (string) [Field Name: name] [Field Type: string (9)] .000 1... = Field Number: 1 .... .010 = Wire Type: Length-delimited (2) Value Length: 13 Value: 6d6163446174612e70726f746f String: macData.proto name: macData.proto Field(2): val (bytes) [Field Name: val] [Field Type: bytes (12)] .001 0... = Field Number: 2 .... .010 = Wire Type: Length-delimited (2) Value Length: 25 Value: 0a1130303a30303a30303a30303a31323a464610eb86b5af06 val: (25 bytes) Encoded Protobuf Protocol Buffers: mac_data.macDataInfo Message: mac_data.macDataInfo [Message Name: mac_data.macDataInfo] Field(1): mac_addr = 00:00:00:00:12:FF (string) [Field Name: mac_addr] [Field Type: string (9)] .000 1... = Field Number: 1 .... .010 = Wire Type: Length-delimited (2) Value Length: 17 Value: 30303a30303a30303a30303a31323a4646 String: 00:00:00:00:12:FF mac_addr: 00:00:00:00:12:FF Field(2): time = 1710048107 (uint64) [Field Name: time] [Field Type: uint64 (4)] .001 0... = Field Number: 2 .... .000 = Wire Type: varint (0) Value: eb86b5af06 Uint64: 1710048107 time: 1710048107