Wireshark Lua dissectors: both expand together - lua

I wrote two simple Wireshark Lua dissectors for chained protocols:
local proto1 = Proto("proto1","First Layer")
local page = ProtoField.uint16("proto1.page", "Page", base.HEX)
proto1.fields = {page}
function proto1.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = proto1.name;
local ptree = tree:add(proto1,buffer(1,5))
ptree:add(page, buffer(1,2))
Dissector.get("proto2"):call(buffer(6, 4):tvb(), pinfo, tree)
end
local proto2 = Proto("proto2","Second Layer")
local len = ProtoField.uint8("proto2.len", "Payload Length")
proto2.fields = {len}
function proto2.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = proto2.name;
local ptree = tree:add(proto2,buffer())
ptree:add(len, buffer(1,2))
end
DissectorTable.get("tcp.port"):add(3456, proto1)
The dissectors do work and display protocols in a tree one after another.
Now if I expand one of the protocols (so a protofield is visible) and click on the other packet, then both proto1 and proto2 in a tree are expanded for an unknown reason.
If I now collapse one of the protocols and click on the other packet, then both are collapsed.
Any advise how to avoid it? My protocols are more complex than shown here, so this expansion makes it hard to analyze.

That's a bug. I could have sworn that was fixed before and then worked correctly. Please submit a bug on bugs.wireshark.org.
In the meantime, you can fake it:
local proto1 = Proto("proto1","First Layer")
local page = ProtoField.uint16("proto1.page", "Page", base.HEX)
local proto2 = ProtoField.bytes("proto2","Second Layer")
local len = ProtoField.uint8("proto2.len", "Payload Length")
proto1.fields = {page, proto2, len}
local function proto2_dissect(buffer, pinfo, tree)
pinfo.cols.protocol = "proto2"
local ptree = tree:add(proto2, buffer()):set_text("Second Layer")
ptree:add(len, buffer(1,2))
end
function proto1.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = proto1.name;
local ptree = tree:add(proto1,buffer(1,5))
ptree:add(page, buffer(1,2))
proto2_dissect(buffer(6,4):tvb(), pinfo, tree)
end
DissectorTable.get("tcp.port"):add(3456, proto1)

Related

How to add an array of fields as a ProtoField in Lua Dissector

I'm writing a Lua Dissector for Wireshark. The packets I'm trying to dissect have the following format:
V_SPEED
N_ITERATION
SEG_LEN[N_ITERATION] --> This means there are N_ITERATION SEG_LEN in my packet
I succeed to add the basic fields (V_SPEED and N_ITERATION) as Wireshark Protofield and I can filter based on those. However I'm struggling for the array of SEG_LEN. I want to be able to use filter like "SEG_LEN[1] == XYZ". How can I achieve that?
For now, I have the following ProtoFields:
myproto = Proto("MyProto", "My Protocol")
myproto.fields.v_speed = ProtoField.uint16("myproto.v_speed", "v_speed", base.DEC)
myproto.fields.n_iteration = ProtoField.uint16("myproto.n_iteration", "n_iteration", base.DEC)
I tried to define a ProtoField for each possible SEG_LEN like so
myproto.fields.seg_len_1 = ProtoField.uint16("myproto.seg_len_1", "seg_len_1", base.DEC)
myproto.fields.seg_len_2 = ProtoField.uint16("myproto.seg_len_2", "seg_len_2", base.DEC)
...
myproto.fields.seg_len_255 = ProtoField.uint16("myproto.seg_len_255", "seg_len_255", base.DEC)
And so I have the following piece of code in my dissector function:
for i0 = 1, N_ITERATION do
seg_len_tmp = extract_variable(buffer, bit_offset, 16)
bit_offset = bit_offset + 16
tree:add(_G["myproto.fields.seg_len"..i0], seg_len_tmp)
end
That way, I guess I would be able to use filter like "SEG_LEN_1 == XYZ".
But wireshark gives me an error saying I'm trying to add a NIL value.
Also, I don't feel like it's a good approach.
I know I can also define a single ProtoField for my seg_len, and add all my seg_len to the tree using the same Protofield, but this will prevent me from filtering with an index.
(English is not my native language, excuse me for the syntax errors)
Something like this?
local myproto = Proto("MyProto", "My Protocol")
local N_ITERATION = 3
-- All the segment lengths in one table
local seg_len = {
[1] = ProtoField.uint16("myproto.seg_len_1", "seg_len_1", base.DEC),
[2] = ProtoField.uint16("myproto.seg_len_2", "seg_len_2", base.DEC),
[3] = ProtoField.uint16("myproto.seg_len_3", "seg_len_3", base.DEC)
}
-- All other fields in a generic pf (protocol fields) table
local pf = {
v_speed = ProtoField.uint16("myproto.v_speed", "v_speed", base.DEC),
n_iteration = ProtoField.uint16("myproto.n_iteration", "n_iteration", base.DEC)
}
-- https://stackoverflow.com/questions/1410862/concatenation-of-tables-in-lua
local function TableConcat(t1, t2)
local i
for i = 1, #t2 do
t1[#t1 + 1] = t2[i]
end
return t1
end
myproto.fields = TableConcat(pf, seg_len)
function myproto.dissector(tvbuf, pinfo, tree)
local offset = 0
myproto_tree = tree:add(myproto, tvbuf(0, -1))
for i = 1, N_ITERATION do
myproto_tree:add(seg_len[i], tvbuf(offset, 2))
offset = offset + 2
end
myproto_tree:add(pf.v_speed, tvbuf(offset, 2))
myproto_tree:add(pf.n_iteration, tvbuf(offset + 2, 2))
end

Whireshark Lua dissector not showing tree

I have packet with trailer data after the packet as in ixia timestamp trailer. I am trying to write a dissector for Wireshark that is quite the same as ixia-packet_trailer plugin. https://raw.githubusercontent.com/boundary/wireshark/master/epan/dissectors/packet-ixiatrailer.c
But i wanted to write in Lua, so it is easiest to change.
I did the lua as heuristic with the function is_my_trailer (as proposed in Wireshark Lua dissector plugin table error), it now stop to show the trailer in ethernet tree so i believe it recognize the pattern 0xae12, but it doesn't show my "my trailer" tree
-- declare our protocol
local my_trailer_proto = Proto("my_trailer","my Trailer")
-- Header fields
local timestamp = ProtoField.uint64 ("my_trailer_proto.timestamp", "timestamp", base.HEX)
local proto_flag = ProtoField.uint8 ("my_trailer_proto.proto_flag", "protoFlag", base.HEX)
local msg_id = ProtoField.uint16("my_trailer_proto.msg_id" , "msdId" , base.HEX)
my_trailer_proto.fields = { timestamp, proto_flag, msg_id }
-- does this packet contains a trailer
local function is_my_trailer(buffer,pinfo,tree)
local length = buffer:len()
if length < 12 then return 1 end
local type = buffer(length-12, 2):uint()
if type == 0xae12 then return true end
return false
end
function my_trailer_proto.dissector(buffer, pinfo, tree)
length = buffer:len()
if length == 0 then return end
local subtree = tree:add(my_trailer_proto, buffer(), "my trailer")
-- Header
subtree:add(timestamp, buffer(length-10,8))
subtree:add(proto_flag, buffer(length-3,1))
subtree:add(msg_id, buffer(length-2,2))
pinfo.cols.protocol = my_trailer_proto.name
pinfo.cols.protocol:set("proto_flag")
pinfo.cols.info:set("proto_flag: " .. proto_flag)
end
my_trailer_proto:register_heuristic("eth.trailer", is_my_trailer)
Here is a pcap file example with the trailer https://transfernow.net/87kwt2k0dne7
You forgot a critical line of code:
if type == 0xae12 then return true end
return false
Should be:
if type == 0xae12 then
my_trailer_proto.dissector(buffer, pinfo, tree)
return true
end
return false
You also have another bug. This line is an error:
pinfo.cols.info:set("proto_flag: " .. proto_flag)
It should be something like:
pinfo.cols.info:set("proto_flag: " .. buffer(length-3,1):uint())

Wireshark dissector decoding 64bit hex

I'm having trouble dissecting 64-bit hex and from what I'm reading the way to do this is using ProtoField.uint64.
I can see this decoding nicely in Wireshark without protofield, though it doesnt work for uint64.
-- declare our protocol
trivial_proto = Proto("triviala","trivial Protocol")
-- create a function to dissect it
function trivial_proto.dissector(buffer,pinfo,tree)
pinfo.cols.protocol = "TRIVIA"
local subtree = tree:add(trivial_proto,buffer(),"Trivia Protocol Data")
subtree:add(buffer(0,2),"Seq number: " .. buffer(0,2):uint())
subtree:add(buffer(2,4),"Seq number: " .. buffer(2,4):uint())
subtree:add(buffer(6,2),"no messages: " .. buffer(6,2):uint())
--Doesnt work
--subtree:add(buffer(8,8),"no messages: " .. buffer(8,8):uint64())
end
-- load the udp.port table
udp_table = DissectorTable.get("udp.port")
-- register our protocol to handle udp port
udp_table:add(20004,trivial_proto)
udp_table:add(20006,trivial_proto)
udp_table:add(20021,trivial_proto)
Wireshark dissecting msgs
When I try exactly the same thing, with the same pcap using ProtoField, I can see my message type "TRIVIA" in wireshark but nothing decoded in its subtree
-- declare our protocol
trivial_proto = Proto("triviala","Trivia Protocol")
local F = trivial_proto.fields
F.f_1 = ProtoField.uint8("triviala.sessnum","Session Number",base.HEX)
F.f_2 = ProtoField.uint32("triviala.seqnum","Sequence Number",base.HEX)
F.f_3 = ProtoField.uint8("triviala.nomsgs","Number Mesages",base.HEX)
F.f_4 = ProtoField.uint64("triviala.time","Date Time",base.HEX)
-- create a function to dissect it
function trivial_proto.dissector(buffer,pinfo,tree)
pinfo.cols.protocol = "TRIVIA"
local subtree = tree:add(trivial_proto,buffer(),"Trivia Protocol Data")
subtree:add(F.f_1, buffer(0,2))
subtree:add(F.f_2, buffer(2,4))
subtree:add(F.f_3, buffer(6,2))
--subtree:add(F.f_4, buffer(8,8))
end
-- load the udp.port table
udp_table = DissectorTable.get("udp.port")
-- register our protocol to handle udp port
udp_table:add(20004,trivial_proto)
udp_table:add(20006,trivial_proto)
udp_table:add(20021,trivial_proto)
Wireshark not dissecting msgs
Please help !
You need to assign trivial_proto.fields to F, not the other way around.
If you refer to the fpm.lua script that is available on the Wireshark Lua/Examples wiki page, you will see that you need to do something like:
local F =
{
f_1 = ProtoField.uint8("triviala.sessnum","Session Number",base.HEX)
f_2 = ProtoField.uint32("triviala.seqnum","Sequence Number",base.HEX)
f_3 = ProtoField.uint8("triviala.nomsgs","Number Mesages",base.HEX)
f_4 = ProtoField.uint64("triviala.time","Date Time",base.HEX)
}
trivial_proto.fields = F
...
subtree:add(F.f_1, buffer(0,2))
subtree:add(F.f_2, buffer(2,4))
subtree:add(F.f_3, buffer(6,2))

How to use Lua field extractor in Wireshark?

I have a protocol like this
"Packet" - A sequence of messages
{Head}{Content}{Head}{Content}...
"Head" - 1 byte
bit 1-7 : msg length
bit 8 : true msg or not
It is a udp communication, I have to use that bit 8 to determine if I need to skip the message.
Following is my toy parser, the Problem I am facing is how to extract the bool value helping me to make the decision.
TOY_proto = Proto("TOY", "TOY Protocol")
local isSkip = ProtoField.new("Is Skip?", "mytoy.isSkip", ftypes.BOOLEAN, {"Yes", "No"}, 8, 0x01)
local msgLen = ProroField.new("Message Length", "mytoy.msgLen", ftypes.UINT8, nil, base.DEC, 0xFE)
TOY_proto.fields = {isSkip, msgLen}
local isSkip_Field = Field.new("mytoy.isSkip")
local function getIsSkip()
return isSkip_Field()()
end
local msgLen_Field = Field.new("mytoy.msgLen")
local function getMsgLen()
return msgLen_Field()()
end
function TOY_proto.dissector(tvbuf, pktinfo, root)
pktinfo.cols.protocol = "TOY"
local pktlen = tvbuf:reported_length_remaining()
local pos = 0
while pos < pktlen do
local headTree = tree:add("Head")
headTree:add_le(isSkip, tvbuf:range(pos,1))
headTree:add_le(msgLen, tvbuf:range(pos,1))
if getIsSkip() then
pos = pos + getMsgLen()
else
-- do something else
end
end
end
udp_table = DissectorTable.get("udp.port")
udp_table:add(6628, TOY_proto)
The Problem is that in the first loop, every variable is doing right, but after the first loop, the value returned from getIsSkip() and getMsgLen() are always unchanged.
When you do this:
return isSkip_Field()()
What you're really doing is logically equivalent to this:
-- extract the FieldInfo object using the Field object "isSkip_Field"
local tempFieldInfo = isSkip_Field()
-- get the Lua boolean value of the FieldInfo object
local tempValue = tempFieldInfo()
-- return it
return tempValue
I mention the above to explain why you're getting what you're getting later in this answer...
When you invoke a field extractor (i.e., you call a Field object to get a FieldInfo object), you actually get back every FieldInfo object of that Field's type that exists in that packet at the time the extractor is invoked. Your packet contains multiple "messages" of your protocol, so in each loop you get back the previous loops' FieldInfo objects as well as the current one, for the same packet.
In other words, when your script executed this:
return isSkip_Field()()
...the first time for a packet, it got back one FieldInfo object, called that, and got the boolean. When it ran the second time, the call to isSkip_Field() actually returned two FieldInfo objects, but it discarded the second one because the code is logically equivalent to the code I wrote at the top of this answer, and instead only called the first instance, which of course rteturns the same boolean value as the first loop iteration; and when it ran a third time for the same packet it returned three FieldInfo objects, discarded the second two, called the first one, etc.
So what you really want to do is select the correct FieldInfo object each loop iteration - namely the most recent (last) one. You can do that one of two ways: (1) using the Lua select() function, or (2) put the returned FieldInfo objects into a table and retrieve the last entry.
For example, do this:
local isSkip_Field = Field.new("mytoy.isSkip")
local function getIsSkip(num)
return select(num, isSkip_Field())()
end
local msgLen_Field = Field.new("mytoy.msgLen")
local function getMsgLen(num)
return select(num, msgLen_Field())()
end
function TOY_proto.dissector(tvbuf, pktinfo, root)
pktinfo.cols.protocol = "TOY"
local pktlen = tvbuf:reported_length_remaining()
local pos = 0
local num = 1
while pos < pktlen do
local headTree = tree:add("Head")
headTree:add_le(isSkip, tvbuf:range(pos,1))
headTree:add_le(msgLen, tvbuf:range(pos,1))
if getIsSkip(num) then
pos = pos + getMsgLen(num)
else
-- do something else
end
num = num + 1
end
end
...or this:
local isSkip_Field = Field.new("mytoy.isSkip")
local function getIsSkip()
local tbl = { isSkip_Field() }
return tbl[#tbl]()
end
local msgLen_Field = Field.new("mytoy.msgLen")
local function getMsgLen()
local tbl = { msgLen_Field() }
return tbl[#tbl]()
end
function TOY_proto.dissector(tvbuf, pktinfo, root)
pktinfo.cols.protocol = "TOY"
local pktlen = tvbuf:reported_length_remaining()
local pos = 0
while pos < pktlen do
local headTree = tree:add("Head")
headTree:add_le(isSkip, tvbuf:range(pos,1))
headTree:add_le(msgLen, tvbuf:range(pos,1))
if getIsSkip() then
pos = pos + getMsgLen()
else
-- do something else
end
end
end
...or if there are going to be lots of Fields, this might be nicer:
local isSkip_Field = Field.new("mytoy.isSkip")
local msgLen_Field = Field.new("mytoy.msgLen")
local function getFieldValue(field)
local tbl = { field() }
return tbl[#tbl]()
end
function TOY_proto.dissector(tvbuf, pktinfo, root)
pktinfo.cols.protocol = "TOY"
local pktlen = tvbuf:reported_length_remaining()
local pos = 0
while pos < pktlen do
local headTree = tree:add("Head")
headTree:add_le(isSkip, tvbuf:range(pos,1))
headTree:add_le(msgLen, tvbuf:range(pos,1))
if getFieldValue(isSkip_Field) then
pos = pos + getFieldValue(msgLen_Field)
else
-- do something else
end
end
end

Wireshark Lua Dissector - How to use a TAP?

I would like to do some analysis on top of my custom protocol that is dissected via my lua dissector. Therefore I tried to do this
myproto_proto = Proto("myproto", "Myproto Protocol")
m_dest = ProtoField.uint16("myproto.dest", "Destination", base.HEX)
m_src = ProtoField.uint16("myproto.src", "Source", base.HEX)
myproto_proto.fields = { sm_dest, sm_src }
dofile(MYPROTO_PROTO_PATH.."parser.lua")
function myproto_proto.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = "MYPROTO"
local subtree = tree:add(myproto_proto, buffer(), "Myproto Protocol Data")
parse_msg(buffer, pinfo, subtree) -- does the actual parsing and sets the fields
end
udp_table = DissectorTable.get("udp.port")
udp_table:add(9000,myproto_proto)
-- LISTENER / TAP
f_test = Field.new("myproto.dest") -- fails because "field does not exist"
local function my_tap()
local window = TextWindow.new("Myproto Tap")
local tap = Listener.new(nil, "myproto")
local counter = 0
function remove()
tap:remove()
end
window:set_atclose(remove)
function tap.packet(pinfo, buffer)
counter = counter + 1
end
function tap.draw(t)
window:append("Counter: \t" .. counter .. "\n")
end
function tap.reset()
window:clear()
counter = 0
end
retap_packets()
end
register_menu("My Tap", my_tap, MENU_TOOLS_UNSORTED)
My problem is, I'm unable to access the dissected data with a field extractor. So how else could I get the dissected data in my lua tap?
Thanks in advance.
It's a known problem that custom Lua Field objects aren't usable in OSX (it apparently works in Windows XP but not Windows 7).
There are a few ways to pass data from your dissector to your tap.
Option 1: Use a shared Lua table
Create a global dictionary that is keyed by the packet number (from pinfo.number, which is visible to both dissector and tap).
-- we omit the 'local' keyword to make `dict` a global variable
dict = {}
In your dissector, add the packet data to the dictionary:
dict[pinfo.number] = { dest = m_dest, src = m_src }
In your tap, you can access the data by a simple lookup.
print('dest', dict[pinfo.number].dest )
XXX: Requires a global; Duplicates storage for a variable that is already held in the protocol tree (and should be accessible from the tap).
Option 2: Use pinfo.private
This was added in the dev build (1.7.0). It's similar to the solution above. pinfo.private is a PrivateTable, which is a hash table that stores only strings.
In your dissector, add your data to the packet's private table:
pinfo.private["src"] = tostring(m_src)
pinfo.private["dest"] = tostring(m_dest)
In your tap, access the data from the pinfo object:
print('dest', pinfo.private["dest"] )
XXX: Can only store string values
Option 3: Reparse the buffer
In your tap, call your parser (i.e., from parser.lua) to reparse the data in buffer, which is passed to the tap.
XXX: Duplicates work already done by dissector (can double processing time for X-large capture files)

Resources