Lua - Display field ASCII Dissector

1.9k views Asked by At

I am currently working on my first ever Protocol Dissector. I am facing a problem that I can't solve. Basically I have a field which is 8 bytes long (but is defined over 9 bytes), so I created a bitfield to define this protofield.

Here are the deffinitions of the field I have tested so far:

a) local harer_id = ProtoField.string   ("myProto.harer_id","Harer ID", base.ASCII)
b) local harer_id =  ProtoField.uint64   ("myProto.harer_id", "Harer ID", base.HEX )

Then I add it to the dissection Tree on the following way:

  local harer_id_long = tvbuf:range(16,9)
  body:add(harer_id, harer_id_long:bitfield(4,64))

Which ends up giving the following errors:

a) Gives no error but it doesnt return the value on ASCII format
    What I get: 0x0000000000313030
    What I want: 0x0000000000313030 (100)
b) calling 'add' on bad self (string expected, got userdata)

If any of you have any suggestions I would appreciate your help.

Thank you in advance,

Martin

EDIT 1:

I wrote this code which will get the ASCII table values from each byte on the field's value:

I don't know how to make it work so that it displays the ASCII value on the packet view.

 function getASCII (str)
    resultStr = ""
    asciiValue="" 
    for i = 3, string.len(tostring(str))-1, 2 do
        asciiValue = string.char(tonumber(tostring(string.sub(tostring(str),i,i+1)), 16))
        if asciiValue~=nil then 
            resultStr = resultStr .. tostring(tonumber(asciiValue))
        end
    end
    resultStr = string.gsub(resultStr, "nil", "") 
    return resultStr
 end
2

There are 2 answers

6
Christopher Maynard On BEST ANSWER

Here is an alternate method that also works for me. I'm not sure which you prefer, but you now have 2 to choose from (assuming you can get my original method to work):

local harer_id = ProtoField.uint64("myProto.harer_id", "Harer ID", base.HEX)

harer_item = body:add(harer_id, tvbuf(16, 9):bitfield(4, 64))
harer_item:set_len(9)

vals = {}
for i = 0, 7 do
    vals[i] = bit.bor(buf(16 + i, 2):bitfield(4, 8), 0x30)
end
harer_item:append_text(" (" ..
    tonumber(string.format("%c%c%c%c%c%c%c%c", vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6], vals[7])) ..
    ")")

EDIT: Here is a simple Lua dissector and sample packet you can use to test this solution:

-- Protocol
local p_foo = Proto("foo", "FOO Protocol")

-- Fields
local f_foo_res1 = ProtoField.uint8("foo.res1", "Reserved 1", base.DEC, nil, 0xf0)
local f_foo_str = ProtoField.uint64("foo.str", "String", base.HEX)
local f_foo_res2 = ProtoField.uint8("foo.res2", "Reserved 2 ", base.DEC, nil, 0x0f)
local f_foo_res3 = ProtoField.uint8("foo.res3", "Reserved 3", base.HEX)
local f_foo_ipv6 = ProtoField.ipv6("foo.ipv6", "IPv6 Address")

p_foo.fields = { f_foo_res1, f_foo_str, f_foo_res2, f_foo_res3, f_foo_ipv6 }

-- Dissection
function p_foo.dissector(buf, pinfo, tree)
    local foo_tree = tree:add(p_foo, buf(0,-1))

    pinfo.cols.protocol:set("FOO")
    foo_tree:add(f_foo_res1, buf(0, 1))

    str_item = foo_tree:add(f_foo_str, buf(0, 9):bitfield(4, 64))
    str_item:set_len(9)

    vals = {}
    for i = 0, 7 do
        vals[i] = bit.bor(buf(i, 2):bitfield(4, 8), 0x30)
    end
    str_item:append_text(" (" ..
        tonumber(string.format("%c%c%c%c%c%c%c%c", vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6], vals[7])) ..
        ")")

    foo_tree:add(f_foo_res2, buf(9, 1))
    foo_tree:add(f_foo_res3, buf(10, 1))
    foo_tree:add(f_foo_ipv6, buf(11, 16))
end

-- Registration
local udp_table = DissectorTable.get("udp.port")
udp_table:add(33333, p_foo)

Use text2pcap to convert this data into a packet that Wireshark can read or use Wireshark's "File -> Import From Hex Dump..." feature:

0000  00 0e b6 00 00 02 00 0e b6 00 00 01 08 00 45 00
0010  00 37 00 00 40 00 40 11 b5 ea c0 00 02 65 c0 00
0020  02 66 82 35 82 35 00 23 00 00 03 03 13 23 33 43
0030  53 63 70 80 64 20 01 0d b8 00 00 00 00 00 00 00
0040  00 00 00 00 01

My Wireshark details:
Compiled (64-bit) with Qt 5.6.2, with WinPcap (4_1_3), with GLib 2.42.0, with zlib 1.2.8, with SMI 0.4.8, with c-ares 1.12.0, with Lua 5.2.4, with GnuTLS 3.4.11, with Gcrypt 1.7.6, with MIT Kerberos, with GeoIP, with nghttp2 1.14.0, with LZ4, with Snappy, with libxml2 2.9.4, with QtMultimedia, with AirPcap, with SBC, with SpanDSP.

2
Christopher Maynard On

There's probably a more efficient way to do this, but you could try something like this?

harer_id = ProtoField.string("myProto.harer_id", "Harer ID", base.ASCII)

harer_item = body:add(harer_id, tvbuf(16, 9))
harer_item:set_text("Harer ID: " ..
    tonumber(
        string.char(bit.bor(bit.band(bit.lshift(tvbuf(16, 1):uint(), 4), 0xf0), bit.rshift(tvbuf(17, 1):uint(), 4))) ..
        string.char(bit.bor(bit.band(bit.lshift(tvbuf(17, 1):uint(), 4), 0xf0), bit.rshift(tvbuf(18, 1):uint(), 4))) ..
        string.char(bit.bor(bit.band(bit.lshift(tvbuf(18, 1):uint(), 4), 0xf0), bit.rshift(tvbuf(19, 1):uint(), 4))) ..
        string.char(bit.bor(bit.band(bit.lshift(tvbuf(19, 1):uint(), 4), 0xf0), bit.rshift(tvbuf(20, 1):uint(), 4))) ..
        string.char(bit.bor(bit.band(bit.lshift(tvbuf(20, 1):uint(), 4), 0xf0), bit.rshift(tvbuf(21, 1):uint(), 4))) ..
        string.char(bit.bor(bit.band(bit.lshift(tvbuf(21, 1):uint(), 4), 0xf0), bit.rshift(tvbuf(22, 1):uint(), 4))) ..
        string.char(bit.bor(bit.band(bit.lshift(tvbuf(22, 1):uint(), 4), 0xf0), bit.rshift(tvbuf(23, 1):uint(), 4))) ..
        string.char(bit.bor(bit.band(bit.lshift(tvbuf(23, 1):uint(), 4), 0xf0), bit.rshift(tvbuf(24, 1):uint(), 4)))
        )
    )