This is our old Q&A Site. Please post any new questions and answers at ask.wireshark.org.

Hi, I am new both to writing dissectors and to lua, but I have anyway managed to write a mostly working set of dissectors for our protocol stack. Thanks a lot for wireshark as a whole and for the lua capabilities. It makes it really easy to work with.

My biggest remaining problem (as in "mostly working") is that my messages can be segmented into several UDP-packets. I cannot figure out how to save the segments for later use and then, when all segments are received, concatenate them.

I would appreciate some hints here.

This could have been my protocol:

--- dissector
local data_dis = Dissector.get ("data")

local p_frag = Proto ("frag", "Frag proto")

local f_frag_message_index = ProtoField.uint32 ("frag.message_index","Message index")
local f_frag_part_index = ProtoField.uint8 ("frag.part_index","Part Index")
local f_frag_part_length = ProtoField.uint8 ("frag.part_length","Part Length")
local f_frag_part_lastIndicator = ProtoField.uint8 ("frag.last_indicator","Last Part Indicator")

p_frag.fields = {f_frag_message_index,
                 f_frag_part_index,
                 f_frag_part_length,
                 f_frag_part_lastIndicator}

function p_frag.dissector(tvb, pinfo, tree)
   local subtree = tree:add (p_frag, tvb())
   subtree:add (f_frag_message_index, tvb(0,4))
   subtree:add (f_frag_part_index, tvb(4,1))
   subtree:add (f_frag_part_length, tvb(5,1))
   subtree:add (f_frag_part_lastIndicator, tvb(6,1))

-- Actually, here I call one of few other dissectors depending of the
-- value of the next byte, bur for this example it would be nice to
-- send the complete message to the data dissector.
   data_dis:call(tvb(7):tvb(),pinfo,subtree)
end

local udp_encap_table = DissectorTable.get("udp.port")
udp_encap_table:add(2900,p_frag)

--- end of dissector

## script to generate a few packets
#!/bin/bash
messageIndex="00000000"
partIndex="00"
partLength="05"
lastIndicator="01"
data="53686f7274"

packetSender() {
    sudo nping 4.3.2.1 --udp -c 1 --source-ip 1.2.3.4 --source-port 2900 --dest-port 2900 --data "$messageIndex$partIndex$partLength$lastIndicator$data"
}

# First complete packet
packetSender

# Then a fragmented packet
# first fragment of index 1
messageIndex="00000001"
partIndex="00"
partLength="04"
lastIndicator="00"
data="4d756368"
packetSender

# Beware, new message!
messageIndex="00000002"
partIndex="00"
partLength="06"
lastIndicator="01"
data="426577617265"
packetSender

#second fragment of index 1
messageIndex="00000001"
partIndex="01"
partLength="06"
lastIndicator="00"
data="2c206d756368"
packetSender

#third and final fragment of index 1
messageIndex="00000001"
partIndex="02"
partLength="07"
lastIndicator="01"
data="206c6f6e676572"
packetSender
## end of packet generating script

asked 17 Sep '16, 08:50

mj99's gravatar image

mj99
26227
accept rate: 50%

edited 22 Sep '16, 14:53

JeffMorriss's gravatar image

JeffMorriss ♦
6.2k572


In case someone wants to do reassembly in lua - this is what I will be using until someone points out improvements:

local data_dis = Dissector.get ("data")

local p_frag = Proto ("frag", "Frag proto")

local f_frag_message_index = ProtoField.uint32 ("frag.message_index","Message index")
local f_frag_part_index = ProtoField.uint8 ("frag.part_index","Part Index")
local f_frag_part_length = ProtoField.uint8 ("frag.part_length","Part Length")
local f_frag_part_lastIndicator = ProtoField.uint8 ("frag.last_indicator","Last Part Indicator")

p_frag.fields = {f_frag_message_index,
                 f_frag_part_index,
                 f_frag_part_length,
                 f_frag_part_lastIndicator}

function p_frag.init ()
   -- print ("(re-)initialise")
   fragments = {}
   concats = {}
end

function p_frag.dissector(tvb, pinfo, tree)
   local subtree = tree:add (p_frag, tvb())

   local messageInd = tvb(0,4):uint()
   subtree:add (f_frag_message_index, tvb(0,4))

   local partInd = tvb(4,1):uint()
   subtree:add (f_frag_part_index, tvb(4,1))
   subtree:add (f_frag_part_length, tvb(5,1))

   local lastFlag = tvb(6,1):uint ()
   subtree:add (f_frag_part_lastIndicator, tvb(6,1))

   if pinfo.visited == false then
      local range = tvb(7)
      local bytes = range:bytes()
      local completeMessage
      local newTvb
      local B = 0
      local F = 1

      if fragments[messageInd] == nil then
         fragments[messageInd] = {}
         -- print ("Creating mess " .. messageInd)
      end

      if fragments[messageInd][partInd] == nil then
         fragments[messageInd][partInd] = {}
         -- print ("Creating mess " .. messageInd .. ", part " .. partInd)
      end

      fragments[messageInd][partInd][B] = bytes
      fragments[messageInd][partInd][F] = lastFlag

      local ind = 0
      completeMessage = ByteArray.new()
      while ind < 8 do -- maximum 8 fragments
         -- print ("Testing ind = " .. ind)
         if fragments[messageInd][ind] ~= nil then
            completeMessage = completeMessage .. fragments[messageInd][ind][B]
         else
            -- print ("No part with that index, break")
            break
         end
         if fragments[messageInd][ind][F] == 1 then
            -- print ("Flag, break!")
            if ind > 0 then
               -- print("pinfo.number = " .. pinfo.number)
               concats[pinfo.number] = completeMessage
               fragments[messageInd] = {}
            end
            break
         end
         ind = ind + 1
      end
   end

   data_dis:call(tvb(7):tvb(),pinfo,subtree)
   if concats[pinfo.number] ~= nil then
      newTvb = ByteArray.tvb(concats[pinfo.number])
      data_dis:call(newTvb(0):tvb(), pinfo, subtree)
   end
end

local udp_encap_table = DissectorTable.get("udp.port")
udp_encap_table:add(2900,p_frag)
permanent link

answered 22 Sep '16, 14:44

mj99's gravatar image

mj99
26227
accept rate: 50%

Ok, now I can concatenate messages spread over several packets. I can however see some problems with my concatenating technique:

  1. It will consume quite some memory since all fragments are saved forever.
  2. I will run into problems when my message indices are reused.

I would prefer to see the message together with dissection of the last received part of the message.

Can the fragments be discarded and the concatenated messages be saved somehow associated with the packet that contains the last part of the message? How is this usually handled?

-- dissector
-- Containing debug prints

fragments = {}

local data_dis = Dissector.get ("data")

local p_frag = Proto ("frag", "Frag proto")

local f_frag_message_index = ProtoField.uint32 ("frag.message_index","Message index")
local f_frag_part_index = ProtoField.uint8 ("frag.part_index","Part Index")
local f_frag_part_length = ProtoField.uint8 ("frag.part_length","Part Length")
local f_frag_part_lastIndicator = ProtoField.uint8 ("frag.last_indicator","Last Part Indicator")

p_frag.fields = {f_frag_message_index,
                 f_frag_part_index,
                 f_frag_part_length,
                 f_frag_part_lastIndicator}

function p_frag.dissector(tvb, pinfo, tree)
   local subtree = tree:add (p_frag, tvb())

   local messageInd = tvb(0,4):uint()
   subtree:add (f_frag_message_index, tvb(0,4))

   local partInd = tvb(4,1):uint()
   subtree:add (f_frag_part_index, tvb(4,1))
   subtree:add (f_frag_part_length, tvb(5,1))

   local lastFlag = tvb(6,1):uint ()
   subtree:add (f_frag_part_lastIndicator, tvb(6,1))

   local range = tvb(7)
   local bytes = range:bytes()
   local completeMessage
   local concatenated = 0
   local newTvb
   local B = 0
   local F = 1

   if fragments[messageInd] == nil then
      fragments[messageInd] = {}
      print ("Creating mess " .. messageInd)
   end

   if fragments[messageInd][partInd] == nil then
      fragments[messageInd][partInd] = {}
      print ("Creating mess " .. messageInd .. ", part " .. partInd)
   end

   fragments[messageInd][partInd][B] = bytes
   fragments[messageInd][partInd][F] = lastFlag

   local ind = 0
   completeMessage = ByteArray.new()
   while ind < 8 do -- maximum 8 fragments
      print ("Testing ind = " .. ind)
      if fragments[messageInd][ind] ~= nil then
         completeMessage = completeMessage .. fragments[messageInd][ind][B]
      else
         print ("No part with that index, break")
         break
      end
      if fragments[messageInd][ind][F] == 1 then
         print ("Flag, break!")
         if ind > 0 then
            print ("Concatenated")
            concatenated = 1
         end
         break
      end
      ind = ind + 1
   end

   data_dis:call(tvb(7):tvb(),pinfo,subtree)
   if concatenated == 1 then
      newTvb = ByteArray.tvb(completeMessage)
      data_dis:call(newTvb(0):tvb(), pinfo, subtree)
   end
end

local udp_encap_table = DissectorTable.get("udp.port")
udp_encap_table:add(2900,p_frag)
permanent link

answered 21 Sep '16, 13:36

mj99's gravatar image

mj99
26227
accept rate: 50%

Impressive - you're probably the first to actually do reassembly in Lua. :-)

[Note that the below is based on my memory of how Wireshark's reassembly code works; I haven't had time to actually review your code.]

Wireshark's internal reassembly routines (which AFAIK aren't available via the Lua API) store the reassembled data forever (note: once the message is reassembled only the reassembled message is stored; the fragments are freed). That's needed because Wireshark is only guaranteed to make a single pass through the file (while loading it) whereas the user may click around (and thus want a full dissection of whatever packet s/he clicks on) and so that reassembly data has to be available without redissecting the earlier (fragment) packets.

The reassembled data is stored such that it's only retrieved when the final frame in the PDU is dissected.

Hope that helps...

(22 Sep '16, 06:18) JeffMorriss ♦

What is impressive is that is possible to do it with so little work. The praise goes to wireshark - or really to all persons involved in creating and maintaining it it.

(22 Sep '16, 13:47) mj99
Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "title")
  • image?![alt text](/path/img.jpg "title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Question tags:

×431
×166
×78
×4

question asked: 17 Sep '16, 08:50

question was seen: 2,660 times

last updated: 22 Sep '16, 14:53

p​o​w​e​r​e​d by O​S​Q​A