Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Here I provide an alternate solution that:

  • Avoids the parent needing to know the child ports
  • Avoids the backward "eth:ethertype:ip:udp:child:parent" problem

This solution relies on the ability of the parent protocol to heuristically determine if the UDP payload handed to it is for the parent dissector or not.

Parent:

local p_parent = Proto("parent", "Parent Protocol")

local child_table = DissectorTable.new("parent.port", "parent.port", ftypes.UINT32, base.DEC, p_parent)
local data_dissector = Dissector.get("data")

-- Fields
local pf = {
    field1 = ProtoField.foo("parent.field1", "Field1", base.FOO),
    field2 = ProtoField.foo("parent.field2", "Field2", base.FOO),
    ...
    fieldN = ProtoField.foo("parent.fieldN", "FieldN", base.FOO)
}
p_parent.fields = pf

-- Dissection
local function dissect_parent(tvbuf, pinfo, tree)

    if tvbuf:len() < PARENT_LENGTH then
        return false
    end

    if -- Any other parent criteria fails
        return false
    end

    -- Assume this packet is for the parent
    local parent_tree = tree:add(p_parent, tvbuf(0, PARENT_LENGTH))
    local offset = 0

    pinfo.cols.protocol:set("Parent")

    parent_tree:add(pf.field1, tvbuf(offset, FIELD1_LENGTH))
    offset = offset + FIELD1_LENGTH
    parent_tree:add(pf.length, tvbuf(offset, FIELD2_LENGTH))
    ...
    offset = offset + FIELD(N-1)_LENGTH
    parent_tree:add(pf.length, tvbuf(offset, FIELDN_LENGTH))

    -- Hand off remainder to child:
    local tvb_sub = tvbuf:range(PARENT_LENGTH, -1):tvb()
    local child

    child = child_table:get_dissector(pinfo.src_port)
    if child ~= nil then
        child(tvb_sub, pinfo, tree)
    else
        child = child_table:get_dissector(pinfo.dst_port)
        if child ~= nil then
            child(tvb_sub, pinfo, tree)
        else
            -- No child registered for this port so hand off to generic data dissector
            data_dissector:call(tvb_sub, pinfo, tree)
        end
    end
    return true
end

function p_parent.dissector(tvbuf, pinfo, tree)
    dissect_parent(tvbuf, pinfo, tree)
end

p_parent:register_heuristic("udp", dissect_parent)

end


Child1:

-- Protocol
local p_child1 = Proto("child1", "Child1 Protocol")

-- Fields
local pf = {
    field1 = ProtoField.foo("child1.field1", "Field1", base.FOO),
    field2 = ProtoField.foo("child1.field2", "Field2", base.FOO),
    ...
    fieldN = ProtoField.foo("child1.fieldN", "FieldN", base.FOO)
}
p_child1.fields = pf

function p_child1.init()
    DissectorTable.get("parent.port"):add(CHILD1_PORT, p_child1)
end

-- Dissection
function p_child1.dissector(tvbuf, pinfo, tree)

    pinfo.cols.protocol:set("Child1")

    local child1_tree = tree:add(p_child1, tvbuf(0, -1))
    local offset = 0
    child1_tree:add(pf.field1, tvbuf(offset, FIELD1_LENGTH))
    offset = offset + FIELD1_LENGTH
    child1_tree:add(pf.field2, tvbuf(offset, FIELD2_LENGTH))
    ...
    offset = offset + FIELD(N-1)_LENGTH
    child1_tree:add(pf.fieldN, tvbuf(offset, FIELDN_LENGTH))
end

And so on for Child2 ... ChildN.