两个具有共享字段的 Wireshark Dissectors

Two Wireshark Dissectors with shared fields

我正在为自定义协议编写 wireshark 解析器。该协议有两个变体,在查看转储时通常无法区分它们。所以通常用户会简单地select解码正确的变体。

这两个变体共享相当多的 ProtoFields 和很多结构,这就是为什么我希望只编写一次大部分的解剖代码,然后让两个顶级解剖器调用它们组件。

大致思路是:

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)

我的问题:当我将 lua 文件放入我的插件目录并启动 wireshark 时,我看到 Wireshark Debug Console(黑色背景而不是白色,带有 lua console) 消息 18:08:56.505 Err LUA PANIC: fields can be registered only once 后跟 Press any key to exit,然后我才能做任何其他事情。按下一个键后,wireshark 立即存在。

如何编写两个具有共享字段的解析器,而不需要太多代码重复?

为什么不只写一个解析器并添加一个 preference 供用户选择要应用的变体?例如:

-- 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)

当然,如果公共 header 中有可用信息可以帮助确定自动应用哪个变体,则根本不需要首选项。