Ask Your Question
0

Chaining two custom dissectors Lua - no such dissector table

asked 2021-10-14 19:34:13 +0000

Jeff82374 gravatar image

I'm attempting to create two Lua dissector files to read a TCP message header and subsequent messages. I would like for the main lua dissector to call a message dissector multiple times based on the number of messages present. I can't seem to get the two to work together without a "no such dissector table" when attempting to reference the other file.

I found the following link, but I'm having trouble determining what goes where in the code. I tried various combinations unsuccessfully, but I'm new to Lua Dissectors. I haven't had much success. https://stackoverflow.com/questions/5...

Any guidance is greatly appreciated.

myHeaderProtocol = Proto("customHeader", "customHeader")
headerId = ProtoField.uint("headerId","headerId", base.DEC)
numMessages = ProtoField.uint("numMessages", "numMessages", base.DEC)
myHeaderProtocol.fields = {headerId, numMessages}

function myHeaderProtocol.dissector(buffer, pinfo, tree)
    length = buffer:len();
    pinfo.cols.protocol = myHeaderProtocol.name

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

--How can I make sure mySubDissector is registered
--And recognized here?
mySubDissector(buffer(2,4):tvb(), pinfo, tree)
mySubDissector(buffer(6,4):tvb(), pinfo, tree)
--Two messages shown for simplicity
end

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

--Where should this go?
        DissectorTable.new("MyCustomTable")

subDissector.lua

mySubDissector = Proto("customHeader", "customHeader")
myMessage = ProtoField.uint("myMessage","myMessage", base.HEX)
mySubDissector.fields = {myMessage}

--Where should this go, or how should I do the equivalent?
function mySubDissector.init()
    DissectorTable.get("MyCustomTable"):add(5678, mySubDissector)
end
function mySubDissector.dissector(buffer, pinfo, tree)
    length = buffer:len();
    pinfo.cols.protocol = mySubDissector.name

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

--I'm not sure about what is below
tcp_table = DissectorTable.get("myHeaderProtocol")
tcp_table:add(5678, mySubDissector)
edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
0

answered 2021-10-15 19:43:15 +0000

cmaynard gravatar image

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 ... (more)

edit flag offensive delete link more

Comments

Thank you for your generous example. I'm still working through it to learn some of the intricacies, but it has helped me a tremendous amount so far.

Jeff82374 gravatar imageJeff82374 ( 2021-10-21 19:37:24 +0000 )edit

Since you indicated that you're new to Lua dissectors, you might want to also have a look at the sample foo.lua file I published on the Wireshark-dev mailing list recently. It closely matches the "Foo" C dissector illustrated in the Wireshark Developer Guide. It's heavily documented, which should make it easier to follow along and may help you with writing your own Lua dissectors, although this foo.lua example dissector is carried over UDP whereas your dissector is carried over TCP, so some additional work is required on your part.

In particular, you're missing TCP reassembly functionality, which should not be overlooked. There are some Lua TCP-based dissectors available that should help you with that though. See the TCP reassembly section of the Lua Dissectors wiki page as well as A dissector tutorial with TCP-reassembly section of the Examples wiki page. I also recently added a ...(more)

cmaynard gravatar imagecmaynard ( 2021-10-21 21:20:04 +0000 )edit

Thanks. I tried to download and review foo.lua. The Link on Wireshark-dev shows that it points to a foo.lua file, but the actual hyperlink redirects to a .bin file below.

https://www.wireshark.org/lists/wires...

Was there another link to the text of foo.lua? Its possible the link is broken or I might not know how to access it.

Jeff82374 gravatar imageJeff82374 ( 2021-10-22 00:55:55 +0000 )edit

I don't know why the file downloads as a .bin file, but just rename it to foo.lua and open it in your editor to view it.

cmaynard gravatar imagecmaynard ( 2021-10-22 05:10:05 +0000 )edit

You can also download it from the MARC Archives. My post is here and the foo.lua attachment can be found towards the bottom.

The Mail Archive is yet another source; my post is here and direct link to the foo.lua attachment is here. In either of these cases, no file renaming is necessary.

cmaynard gravatar imagecmaynard ( 2021-10-22 05:43:00 +0000 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2021-10-14 19:34:13 +0000

Seen: 767 times

Last updated: Oct 15 '21