Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

For the header protocol, you're creating the DissectorTable but you're not saving the return value or doing anything with it. Your dissector table also appears to be based on a port number, which is a 16-bit value, so you should explicitly specify that as the type. If it is in fact a port number, then I find myself questioning why there are 2 different protocols involved here at all, but I'll assume there's a good reason you're doing this. Besides the problems with the subdissector table:

  • The filter names aren't following the <protocol>.<field> naming convention.
  • There is no ProtoField.uint function. Since both fields of the header are 1 byte, you should be using ProtoField.uint8 instead.

As for the subdissector, apart from the same problems with filter names and ProtoField.uint, which should be ProtoField.uint32 in this case, there's nothing else that needs to change.

Below are some modified code samples that should help.


First, the header: There are at least 2 ways to call the subdissector and I've illustrated both. You can even try out either method by changing the "Subdissection Method" preference.

myHeaderProtocol = Proto.new("myHeader", "My Custom Header Protocol")

-- Define protocol fields
local pf = {
    headerId = ProtoField.uint8("myHeader.headerId", "headerId", base.DEC),
    numMessages = ProtoField.uint8("myHeader.numMessages", "numMessages", base.DEC)
}
myHeaderProtocol.fields = pf

local myCustomTable = DissectorTable.new("MyCustomTable", "MyCustomTable", ftypes.UINT16, base.DEC)

-- Preferences
local METHOD_TRY    = 1
local METHOD_CALL   = 2
local methods_table = {
    {1, "Try", METHOD_TRY},
    {2, "Call", METHOD_CALL}
}
local default_prefs = {
    subdissectionMethod = METHOD_TRY
}
myHeaderProtocol.prefs.subdissection_method = Pref.enum("Subdissection Method",
    default_prefs.subdissectionMethod,
    "The subdissection method as \"try\" or \"call\".",
    methods_table,
    false
    )

function myHeaderProtocol.dissector(buffer, pinfo, tree)

    pinfo.cols.protocol = myHeaderProtocol.name

    local subtree = tree:add(myHeaderProtocol,buffer(), "Header Tree")
    subtree:add(pf.headerId, buffer(0, 1))
    subtree:add(pf.numMessages, buffer(1, 1))

    local numMessages = buffer(1, 1):uint()
    local offset = 2

    if myHeaderProtocol.prefs.subdissection_method == METHOD_TRY then
        --[[
            This method will use dissectortable:try().
            Note that we must still check if there's a subdissector
            registered; otherwise the data dissector will be called for us
            automatically if there isn't a registered dissector, and we don't
            want that.
        --]]
        local port

        if myCustomTable:get_dissector(pinfo.src_port) ~= nil then
            port = pinfo.src_port
            --pinfo.cols.info:append(" Source Port Match")
        elseif myCustomTable:get_dissector(pinfo.dst_port) ~= nil then
            port = pinfo.dst_port
            --pinfo.cols.info:append(" Destination Port Match")
        else
            return
        end

        while numMessages > 0 do
            myCustomTable:try(port, buffer(offset, 4):tvb(), pinfo, tree)
            offset = offset + 4
            numMessages = numMessages - 1
        end
    elseif myHeaderProtocol.prefs.subdissection_method == METHOD_CALL then
        --[[
            This method will call the subdissector directly if a handle is
            successfully found in the subdissector table.
        --]]
        local subdissector_handle = myCustomTable:get_dissector(pinfo.src_port)

        if subdissector_handle == nil then
            subdissector_handle = myCustomTable:get_dissector(pinfo.dst_port)
        end

        if subdissector_handle ~= nil then
            while numMessages > 0 do
                subdissector_handle:call(buffer(offset, 4):tvb(), pinfo, tree)
                offset = offset + 4
                numMessages = numMessages - 1
            end
        end
    end
end

tcp_table = DissectorTable.get("tcp.port")
tcp_table:add(5678, myHeaderProtocol)

And the subdissector:

mySubDissector = Proto.new("mySubDissector", "My Sub Dissector")

local pf = {
    myMessage = ProtoField.uint32("mySubDissector.Message", "Message", base.HEX)
}
mySubDissector.fields = pf

function mySubDissector.init()
    DissectorTable.get("MyCustomTable"):add(5678, mySubDissector)
end

function mySubDissector.dissector(buffer, pinfo, tree)
    pinfo.cols.protocol = mySubDissector.name

    local subtree = tree:add(mySubDissector, buffer(), "Message SubTree")
    subtree:add(pf.myMessage, buffer(0, 4))
end