How to get parent and child dissector to work at both TCP and ethertype levels
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)
What purpose does the "parent" serve? Why not just have the child directly register in the "tcp.port" table?
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)
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
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)
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)
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?