I am writing a wireshark dissector for a custom protocol. The protocol has two variants, which are indistinguishable in general when looking at the dump. So usually the user will simply select the correct variant to decode.
Both variants share quite a lot of ProtoField
s and also a lot of structure, which is why I had hoped to write most of the dissection code only once and then have two top-level dissectors calling those components.
The rough idea is:
local custom_var1 = Proto("custom_var1", "My custom protocol Variant 1")
local custom_var2 = Proto("custom_var2", "My custom protocol Variant 2")
-- my actual header and data blocks are a lot more complex than single integers of course
local header = ProtoField.uint8("custom.head", "Header")
local data1 = ProtoField.uint64("custom.data1", "Data 1")
local data2 = ProtoField.uint32("custom.data2", "Data 2")
local data3 = ProtoField.uint8("custom.data3", "Data 3")
custom_var1.fields = {header, data1, data2}
custom_var2.fields = {header, data1, data2, data3}
local function dissect_header(tvb, tree)
tree:add(header, tvb(0, 1))
end
local function dissect_data1(tvb, tree)
tree:add(data1, tvb(0, 8))
end
local function dissect_data2(tvb, tree)
tree:add(data2, tvb(0, 4))
end
local function dissect_data3(tvb, tree)
tree:add(data3, tvb(0, 1))
end
function custom_var1.dissector(tvb, pinfo, root)
pinfo.cols.protocol:set(custom_var1.name)
local tree = root:add(custom_var1, tvb(0, 13))
dissect_header(tvb(0), tree)
dissect_data1(tvb(1), tree)
dissect_data2(tvb(9), tree)
end
function custom_var2.dissector(tvb, pinfo, root)
pinfo.cols.protocol:set(custom_var2.name)
local tree = root:add(custom_var2, tvb(0, 14))
dissect_header(tvb(0), tree)
dissect_data2(tvb(1), tree)
dissect_data1(tvb(5), tree)
dissect_data3(tvb(13), tree)
end
tcp_port = DissectorTable.get("tcp.port")
tcp_port:add(31337, custom_var1)
tcp_port:add(31337, custom_var2)
My problem: When I place the lua file into my plugin directory and start wireshark, I see a Wireshark Debug Console
(with black background and not white, a with the lua console) with the message 18:08:56.505 Err LUA PANIC: fields can be registered only once
followed by Press any key to exit
before I can do anything else. After pressing a key, wireshark immediately exists.
How can I write two dissectors with shared fields, without too much code duplication?
Why not just write one dissector and add a preference for the user to choose which variant to apply? For example:
-- Protocol
local p_custom = Proto("custom", "My custom protocol")
local data_dis = Dissector.get("data")
-- Preferences
local default_settings = {
variant = 1
}
local variant_pref_enum = {
{ 1, "1", 1 },
{ 2, "2", 2 }
}
p_custom.prefs.variant = Pref.enum("Variant", default_settings.variant,
"The variant", variant_pref_enum)
-- Fields
local pf = {
header = ProtoField.bytes("custom.head", "Header"),
data1 = ProtoField.uint64("custom.data1", "Data 1"),
data2 = ProtoField.uint32("custom.data2", "Data 2"),
data3 = ProtoField.uint8("custom.data3", "Data 3")
}
p_custom.fields = pf
-- Dissection
function p_custom.dissector(tvbuf, pinfo, tree)
local custom_tree = tree:add(p_custom, tvbuf(0, -1))
custom_tree:add(pf.header, tvbuf(0, 1))
if p_custom.prefs.variant == 1 then
-- Dissect Variant 1
pinfo.cols.protocol:set("CUSTOM 1")
custom_tree:append_text(": Variant 1")
custom_tree:add(pf.data1, tvbuf(1, 8))
custom_tree:add(pf.data2, tvbuf(9, 4))
elseif p_custom.prefs.variant == 2 then
-- Dissect Variant 2
pinfo.cols.protocol:set("CUSTOM 2")
custom_tree:append_text(": Variant 2")
custom_tree:add(pf.data2, tvbuf(1, 4))
custom_tree:add(pf.data1, tvbuf(5, 8))
custom_tree:add(pf.data3, tvbuf(13, 1))
else
-- Unknown Variant
pinfo.cols.protocol:set("CUSTOM ?")
custom_tree:append_text(": Unknown Variant")
data_dis:call(tvbuf:range(1, tvbuf:len() - 1):tvb(), pinfo, tree)
end
end
-- Registration
local tcp_port = DissectorTable.get("tcp.port")
tcp_port:add(31337, p_custom)
Of course, if there's information available in the common header that can help determine which variant to apply automatically, then a preference isn't needed at all.