Ask Your Question
0

How to get parent and child dissector to work at both TCP and ethertype levels

asked 2021-12-01 15:18:44 +0000

Jeff82374 gravatar image

I'm fairly new to Lua dissectors, and I have a custom parent and child dissector that currently work over TCP port 5001. My custom protocol can also dissect the same protocol over ethernet (not TCP) if I modify the entire example to use hardcoded ethertype and 0x8800 instead of tcp and 5001.

How can I make the parent and child generic enough to work over either TCP port 5001 or ethertype 0x8800? I'm trying to minimize duplication and make modules as reusable as possible.

Challenge 1: MyCustomTable Dissector Table is shared across LUA files. If I create a separate parent ethertype file with a different MyCustomTable2 name, this no longer matches child. How can the child know which parent dissector table to pull (MyCustomTable or MyCustom Table2)?

Challenge 2: Child is currently hardcoded to TCP port 5001. I can add if statements to change these hardcoded values, but I don't know how to find out if the parent is ethertype or tcp to decide at the child.lua file level.

Thanks!

--child.lua

 MyProtocolA = Proto.new("MyProtocolA", "My Protocol A")

--ProtoFields and Fields defined but not shown

function MyProtocolA.init()

        DissectorTable.get("MyCustomTable"):add(5001, MyProtocolA)
    end

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

    local subtree = tree:add(MyProtocolA,buffer(), "My Protocol Data")

    --More here not shown
end

tcp_table = DissectorTable.get("tcp.port")
tcp_table:add(5001, MyProtocolA)

--parent.lua

MyParent = Proto.new("MyParent", "MyParent")

--Protofields and Fields defined here

local MyTable = DissectorTable.new("MyCustomTable",
                                   "MyCustomTable", ftypes.UINT32, base.HEX)

function MyParent.dissector(buffer, pinfo, tree)
    local payloadLength = buffer:len()
    pinfo.cols.protocol = MyParent.name
    local subtree = tree:add(MyParent,buffer(), "MyParent")

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

    nextBlock = -- get next bytes to process here
    subdissector_handle:call(nextBlock,pinfo,subtree)
end

tcp_table = DissectorTable.get("tcp.port")
tcp_table:add(5001, MyParent)
edit retag flag offensive close merge delete

Comments

I'm fairly new to Lua dissectors, and I have a custom parent and child dissector

What purpose does the "parent" serve? Why not just have the child directly register in the "tcp.port" table?

that currently work over TCP port 5001. My custom protocol can also dissect the same protocol over ethernet (not TCP)

TCP is a byte-stream protocol, with no service offered to protocols running atop it to send a message as a unit; any protocol that sends messages needs to provide some mechanism to determine where one message begins and the other one ends. For binary protocols, this is frequently done by adding a message length, in bytes, at the beginning of the message.

Ethernet is a frame-oriented protocol, with distinct boundaries between frames, so a protocol running atop Ethernet normally puts one message in one Ethernet frame.

In what fashion does the protocol in question run ...(more)

Guy Harris gravatar imageGuy Harris ( 2021-12-02 01:46:30 +0000 )edit

In my case, the parent might contain N children, but the child dissector only dissects one at a time. I use the parent to handle multiple children.

In my case, the Ethernet packets are sent over 10 Gbit connection, so there is an proprietary protocol in between ethernet and parent that I forgot to include.

Thanks for your input. cmaynard's answer fixed the issues that I had

Jeff82374 gravatar imageJeff82374 ( 2021-12-02 15:04:46 +0000 )edit

I've also been confused by this whole parent/child thing. To me, it doesn't really seem like you have 2 different protocols at all, but rather one protocol consisting of some header (of fixed or possibly variable length) plus N blocks of data. It really seems to me like you just need one protocol dissector to handle all of this.

And I also mentioned previously about proper handling of TCP reassembly in one of my comments to your other question. In that question, you hadn't yet mentioned anything about Ethertype 0x8800, but if this protocol is carried directly atop Ethernet, then in order to make it robust, you're going to have to perform reassembly yourself in that case, obviously with no help from the TCP dissector. I don't really see how having a 10 Gbit connection negates reassembly woes ... unless your protocol data is so ...(more)

cmaynard gravatar imagecmaynard ( 2021-12-02 16:25:30 +0000 )edit

Thanks. I simplified the original scenario as much as possible, so that left out detail that is causing confusion. I'll clarify below. I have things working now thanks to your help.

In my case my messages do not cross packet or frame boundaries if they do not fit evenly. If N messages will not fit in one ethernet frame, N-1 messages are sent and unused filler bytes are added to fill remaining space.

Here are my two scenarios to clarify. The parent / child architecture was implemented to reduce redundancy and improve modularity.

Case 1: TCP packet -> Parent Dissector that groups N child messages -> Child messages (Child1, Child2, and ChildN messages are different message types and message sizes with their own .lua dissectors. Only one child message type is sent per packet)

Case 2: Ethernet Frame -> IntermediateProtocol(Not Previously Mentioned)-> Parent Dissector that groups M child ...(more)

Jeff82374 gravatar imageJeff82374 ( 2021-12-02 18:20:21 +0000 )edit

In my case my messages do not cross packet or frame boundaries if they do not fit evenly.

By "packet ... boundaries" do you mean TCP segment boundaries? If so, then by what mechanism can you ensure that messages never cross TCP segment boundaries?

Guy Harris gravatar imageGuy Harris ( 2021-12-02 20:29:33 +0000 )edit

1 Answer

Sort by ยป oldest newest most voted
0

answered 2021-12-02 01:23:46 +0000

cmaynard gravatar image

First, I really don't understand why the child registers with the TCP dissector table at all. The child only needs to register with the parent.

Below are modified parent/child Lua pseudo-code that should work ... assuming the child is the only one (i.e., there are no other children that register with the parent):

Parent

MyParent = Proto.new("MyParent", "My Parent Protocol")

--Protofields and Fields defined here

local MyParentTable = DissectorTable.new("MyParentTable", "MyParentTable", ftypes.STRING, base.NONE)

function MyParent.dissector(buffer, pinfo, tree)

    pinfo.cols.protocol = MyParent.name

    local subtree = tree:add(MyParent, buffer(), "My Parent")

    -- Add parent fields here

    -- Subdissection:
    local nextBlock = -- get next bytes to process here
    MyParentTable:try("MyProtocolA", nextBlock, pinfo, subtree)
end

DissectorTable.get("tcp.port"):add(5001, MyParent)
DissectorTable.get("ethertype"):add(0x8800, MyParent)

Child

MyProtocolA = Proto.new("MyProtocolA", "My Protocol A")

--ProtoFields and Fields defined but not shown

function MyProtocolA.init()
    DissectorTable.get("MyParentTable"):add("MyProtocolA", MyProtocolA)
end

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

    local subtree = tree:add(MyProtocolA, buffer(), "My Protocol A Data")

    --More here not shown
end

--[[
    -- This should also work instead of being done in MyProtocolA.init(),
    -- at least it did in my testing.
    DissectorTable.get("MyParentTable"):add("MyProtocolA", MyProtocolA)
--]]
edit flag offensive delete link more

Comments

Thanks for the detailed example. I was able to structure my code as you described to get the dissector to work more elegantly.

I did have to include the DissectorTable.get("MyParentTable"):add("MyProtocolA", MyProtocolA) line in the init() function.

In my case, if this command was located at the of the code, I get an "attempt to index a nil value" error. I'll keep it in then init() function for now.

Much appreciated.

Jeff82374 gravatar imageJeff82374 ( 2021-12-02 15:08:35 +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-12-01 15:18:44 +0000

Seen: 507 times

Last updated: Dec 02 '21