ANNOUNCEMENT: Live Wireshark University & Allegro Packets online APAC Wireshark Training Session
April 17th, 2024 | 14:30-16:00 SGT (UTC+8) | Online

Wireshark-dev: Re: [Wireshark-dev] Intro and lua question

From: Peter Wu <peter@xxxxxxxxxxxxx>
Date: Fri, 21 Oct 2016 23:47:59 +0200
On Fri, Oct 21, 2016 at 01:24:52PM -0700, Jerry White wrote:
> Hi,
[..]
> Advanced packet
> <tcp header stuff>
> <MyProto fixed length header><MyProto variable length data>
> <MyProto fixed length header><MyProto variable length data>
> <MyProto fixed length header><MyProto variable length data>
> 
> This packet has three application transactions in it. The first 8 bytes of
> the MyProto header are always the same, and I can count from there into the
> packet to parse out the fields I need. The problem is, since the data
> section is variable length, I don't know where to look for the next header.
> How do I do that in lua?

As Michael noted, if the length can be derived from the header, then you
can use the dissect_tcp_pdus Lua function (in the C library code it is
called tcp_dissect_pdus instead. It is documented at
https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Proto.html

Here is an example of using dissect_tcp_pdus, it has abirtrary numbers,
but it should show the idea. Read mgi.dissector first, then
get_mgi_length, then dissect_mgi for a better understanding.
Documentations link follow, here is the code:

    function get_mgi_length(tvb, pinfo, offset)
        -- Note: tvb(...) and tvb:range(...) both create a TvbRange,
        -- prefer the former since it is more efficient (it saves a
        -- method lookup)

        -- When you access a TvbRange as string, then the __tostring
        -- method will be used which is typically not what you want.
        -- Therefore invoke int, string, etc. for as appropriate
        local msgid = tvb(offset, 4):uint()

        if msgid == 1234 then
            -- Assume this field contains the length following the header
            local datalen = tvb(offset + 4, 4):uint()

            return 19 + datalen
        elseif msgid == 4567 then
            -- Example that shows what to do if you need more bytes to
            -- know the actual length: the real length is stored in four
            -- bytes at offset 20.

            if tvb:reported_len() < offset + 20 + 4 then
                -- special value (supported since 2.0) that indicates
                -- that more bytes are needed to know PDU length
                return 0
            end

            -- Length is definitely valid, so can safely read length now
            local datalen = tvb(offset + 20, 4):uint()
            return 19 + datalen
        else
            -- In other cases, assume just the fixed-length header
            return 19
        end
    end

    function dissect_mgi(tvb, pinfo, tree)
        pktinfo.cols.info:set("MSGID=")

        -- note: changed from tvb:range() to tvb()
        local info_mgi_msg_id = tvb(9, 10)
        -- example of using :string() to print a hex string instead of
        -- some hexadecimal representation
        pktinfo.cols.info:append(info_mgi_msg_id:string())

        -- etc.
    end

    function mgi.dissector(tvb, pinfo, tree)
        -- Assume that you need to know at least 19 bytes for retrieving
        -- the length. Then when at least 19 bytes are available, call
        -- get_mgi_length to find the real length. If the full data is
        -- available, call dissect_mgi to handle it.
        dissect_tcp_pdus(tvb, tree, 19, get_mgi_length, dissect_mgi)
    end

The full reference manual of the Lua interface exposed by Wireshark is
available at
https://www.wireshark.org/docs/wsdg_html_chunked/wsluarm_modules.html

The dissect_tcp_pdus function is documented in the "Global Functions"
section at
https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Proto.html
-- 
Kind regards,
Peter Wu
https://lekensteyn.nl