Dealing with segmented data in a Wireshark dissector written in Lua


Protocols based on stream-oriented transport protocols like TCP may get segmented i.e. the PDU boundaries may not be preserved. If you are not familiar with writing dissectors for Wireshark in Lua, read Create a Wireshark dissector in Lua.

Protocols based on TCP

You can simply let the TCP dissector reassemble segments by telling it how much data the dissector function still needs.

Adding the following logic to the dissector function does the trick. Reading the PDU length field is protocol specific, change it appropriately.

    local i = 0
    repeat
        if buf:len() - i >= 2 then    -- change length field size appropriately
            -- we have length field
            i = i + buf(i,2):uint() -- change appropriately
            if i > buf:len() then
                -- we don't have all the data we need yet
                pkt.desegment_len = i - buf:len() 
                return
            end
        else
            -- we don't have all of length field yet
            pkt.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 
            return
        end
    until i >= buf:len()
    
    -- rest of the dissector function remains the same,
    -- but use a repeat / until loop to read all PDUs

The TCP dissector calls the dissector function with progressively larger chunks of data taken by aggregating data from the following TCP segments. Once data has been aggregated, your dissector function will proceed as usual.

Protocols not based on TCP

If your protocol is not based on TCP, you will have to handle segmentation on your own. It bears to keep in mind that Wireshark will call the dissector function for each packet, from first to the last, when you first open a capture file. This knowledge can be used to preprocess each packet, and save some state information such as whether it is segmented or not. If it is segmented, its raw data can be appended to a global byte array. This process will repeat until the whole message is ascertained to have been read. A new Tvb can then be created and used for dissection. The final byte array is saved in state of the last packet in sequence.

    local state = pktState[pkt.number]

    if state ~= nil then
        -- we've already processed this packet
        if state.complete == true then
            pkt.info = "Command [complete]"
            buf = ByteArray.tvb(state.buffer, "Complete Command")
        else
            pkt.info = "Command [incomplete]"
            return -- nothing to do
        end
    else
        -- first time here, capture file has just been opened?
        state = {}
        if partialBuffer == nil then
            partialBuffer = buf(0):bytes()
        else
            partialBuffer:append(buf(0):bytes())
            buf = ByteArray.tvb(partialBuffer, "Command") -- create new tvb for packet
        end
        local i = 0
        repeat
            if buf:len() - i >= 2 then -- change length field size appropriately
                -- we have length field
                i = i + buf(i,2):uint() -- change appropriately
                if i > buf:len() then
                    -- we don't have all the data we need yet
                    state.complete = false 
                    pktState[pkt.number] = state
                    return
                end
            else
                -- we don't have all of length field yet
                state.complete = false 
                pktState[pkt.number] = state
                return
            end
        until i >= buf:len()
        state.complete = true
        state.buffer = partialBuffer
        pktState[pkt.number] = state
        partialBuffer = nil
    end

    -- perform dissection of buf

Remember to initialize pktState to an empty table i.e. {} in the init function. partialBuffer is a file local variable used within the dissector function.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s