| 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