Wireshark Lua Dissector - How to use a TAP? - lua

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)

Related

Profinet LUA dissector without ports to extract specific bits

How can I make a Lua dissector/post-dissector/chained dissector that would get attached under the PROFINET IO Cyclic Service Data Unit and for example extract only the last 3 bits of the 5th byte, highlighted in the image below?
All the examples of Lua dissectors I could find are attached to some ports. Profinet does not use TCP/IP layer so there are no ports to attach to.
You should be able to achieve what you want using the following example as a rough guide, where I illustrate both how to add the field to the tree as well as to grab the data and do something with it (e.g., append the relevant data to the Info column):
local pn_io_post = Proto("PNIOPost", "PNIO Postdissector")
local pf = {
afield = ProtoField.uint8("pn_io_post.afield", "A Field", base.DEC, nil, 0x03, "A Field Description")
}
pn_io_post.fields = pf
local pn_io_data = Field.new("pn_io")
function pn_io_post.dissector(tvbuf, pinfo, tree)
local pn_io_post_tree
local pn_io_data_ex = pn_io_data()
if pn_io_data_ex ~= nil then
local pn_io_data_tvb = pn_io_data_ex.range()
local afield
pn_io_post_tree = tree:add(pn_io_post, pn_io_data_tvb(0, -1))
pn_io_post_tree:add(pf.afield, pn_io_data_tvb(4, 1))
afield = pn_io_data_tvb(4, 1):uint()
afield = bit.band(0x03, afield)
pinfo.cols.info:append(" [A Field = " .. afield .. "]")
end
end
register_postdissector(pn_io_post)

LUA: Looking for a specific table by its variable

I'm currently starting work on a text adventure game in Lua--no addons, just pure Lua for my first project. In essence, here is my problem; I'm trying to find out how I can do a "reverse lookup" of a table using one of its variables. Here's an example of what I've tried to do:
print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
table.insert(bag,gold)
print("You took the " .. gold.name .. ".")
end
Obviously, writing a line like this with every single object in the game would be very... exhausting--especially since I think I'll be able to use this solution for not just taking items but movement from room to room using a reverse lookup with each room's (x,y) coordinates. Anyone have any ideas on how to make a more flexible system that can find a table by the player typing in one of its variables? Thanks in advance!
-blockchainporter
This doesn't directly answer your question as you asked it, but I think it would serve the purpose of what you are trying to do. I create a table called 'loot' which can hold many objects, and the player can place any of these in their 'bag' by typing the name.
bag = {}
loot = {
{name="Gold", qty=3},
{name="Axe", qty=1},
}
print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
if (x == loot[i].name) then
table.insert(bag, table.remove(loot,i))
else
i = i + 1
end
end
For bonus points, you could check 'bag' to see if the player has some of that item already and then just update the quantity...
while loot[i] do
if (x == loot[i].name) then
j, found = 1, nil
while bag[j] do
if (x == bag[j].name) then
found = true
bag[j].qty = bag[j].qty + loot[i].qty
table.remove(loot,i)
end
j = j + 1
end
if (not found) then
table.insert(bag, table.remove(loot,i))
end
else
i = i + 1
end
end
Again, this isn't a 'reverse lookup' solution like you asked for... but I think it is closer to what you are trying to do by letting a user choose to loot something.
My disclaimer is that I don't use IO functions in my own lua usage, so I have to assume that your x = io.read("*l") is correct.
PS. If you only ever want objects to have a name and qty, and never any other properties (like condition, enchantment, or whatever) then you could also simplify my solution by using key/val pairs:
bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }
print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
if x == name then
bag.name = (bag.name or 0) + qty
loot.name = nil
end
end
I have a few notes to start before I specifically address your question. (I just want to do this before I forget, so please bear with me!)
I recommend printing to the terminal using stderr instead of stdout--the Lua function print uses the latter. When I am writing a Lua script, I often create a C-style function called eprintf to print formatted output to stderr. I implement it like this:
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
Just be aware that, unlike print, this function does not automatically append a newline character to the output string; to do so, remember to put \n at the end of your fmt string.
Next, it may be useful to define a helper function that calls io.read("*l") to get an entire line of input. In writing some example code to help answer your question, I called my function getline--like the C++ function that has similar behavior--and defined it like this:
local function getline()
local read = tostring(io.read("*l"))
return read
end
If I correctly understand what it is you are trying to do, the player will have an inventory--which you have called bag--and he can put items into it by entering item names into stdin. So, for instance, if the player found a treasure chest with gold, a sword, and a potion in it and he wanted to take the gold, he would type Gold into stdin and it would be placed in his inventory.
Based on what you have so far, it looks like you are using Lua tables to create these items: each table has a name index and another called ap; and, if a player's text input matches an item's name, the player picks that up item.
I would recommend creating an Item class, which you could abstract nicely by placing it in its own script and then loading it as needed with require. This is a very basic Item class module I wrote:
----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item
-- __newindex metamethod.
function Item.__newindex(self, k, v)
local err = string.format(
"type `Item` does not have member `%s`",
tostring(k)
)
return error(err, 2)
end
-- Item constructor
function Item.new(name_in, ap_in)
assert((name_in ~= nil) and (ap_in ~= nil))
local self = {
name = name_in,
ap = ap_in
}
return setmetatable(self, Item)
end
return Item
From there, I wrote a main driver to encapsulate some of the behavior you described in your question. (Yes, I know my Lua code looks more like C.)
#!/usr/bin/lua
-------------
-- Modules --
-------------
local Item = assert(require("Item"))
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
local function printf(fmt, ...)
io.stdout:write(string.format(fmt, ...))
return
end
local function getline()
local read = tostring(io.read("*l"))
return read
end
local function main(argc, argv)
local gold = Item.new("Gold", 3)
printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
return 0
end
main(#arg, arg)
Now, as for the reverse search which you described, at this point all you should have to do is check the user's input against an Item's name. Here it is in the main function:
local function main(argc, argv)
local gold = Item.new("Gold", 3)
local bag = {}
eprintf("What are you trying to take? ")
local input = getline()
if (input == gold.name) then
table.insert(bag, gold)
eprintf("You took the %s.\n", gold.name)
else
eprintf("Unrecognized item `%s`.\n", input)
end
return 0
end
I hope this helps!

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))

Reading artist metadata from DBus in lua script - weird output

I'm trying to reading in DBus metadata from nuvolaplayer in a Lua script. The (track) title and album fields display as expect, but the artist data appears oddly:
lgi.rec 0x7f9ee8005c90:GLib.Variant Underwater Dub Dictionary
Where "Sly & Robbie" is expected in place of "lgi.rec 0x7f9ee8005c90:GLib.Variant".
When I look at the value using d-feet, I can see that the xesam:artist field differs from the others in being surrounded by []s.
Here's the code I'm using:
local lgi = require 'lgi'
local Gio = lgi.require 'Gio'
local core = require 'lgi.core'
local GLib = lgi.require 'GLib'
local type,unpack = type,unpack
local bus = Gio.bus_get_sync(Gio.BusType.SESSION)
local ret,err = bus:call(
"org.mpris.MediaPlayer2.nuvolaplayer",
--"org.gnome.Rhythmbox3",
"/org/mpris/MediaPlayer2",
"org.freedesktop.DBus.Properties",
"GetAll",
GLib.Variant.new_tuple(
{
GLib.Variant("s","org.mpris.MediaPlayer2.Player")
}, 1),
nil,
Gio.DBusConnectionFlags.NONE,
-1, -- Timeout
nil, -- Cancellable
function(conn, res)
local ret, err = bus:call_finish(res)
print("here",err)
local returnValue1, returnValue2 = unpack(ret.value)
if not err then
print("META", returnValue1.Metadata["xesam:artist"],
returnValue1.Metadata["xesam:album"],
returnValue1.Metadata["xesam:title"])
end
end
)
local main_loop = GLib.MainLoop()
main_loop:run()
The field xesam:artist is a list/array of strings (artists). Maybe Lua needs special handling of this type for printing, for example iterate the array and extract plain strings from it.

Can I extract stack values from a parent function in Lua?

My game engine pushes a value on to the lua stack as a parameter to a function and then invokes it using lua_pcall. The lua code will run and call additional lua functions. Eventually this lua code will invoke a C function. Is it possible for this function to retrieve the value that was originally pushed on to the stack?
Its like this:
<engine function A>
pushes parameter value X on to stack for lua
<lua func>
<lua func>
<lua func>
<engine function B>
can I extract the values X that was pushed by function A here?
Yes, with a combination of getinfo, getlocal and getupvalue you can get all that information (you can even change those values using set* functions).
Here is a fragment from MobDebug that returns stack information along with a table of locals and upvalues at each level. The variables at each level will be indexed in the same order they appear in the code (starting from parameters). For each get* function you can use their C equivalents (lua_getinfo, lua_getlocal, and lua_getupvalue), but the logic should be exactly the same.
local function stack(start)
local function vars(f)
local func = debug.getinfo(f, "f").func
local i = 1
local locals = {}
while true do
local name, value = debug.getlocal(f, i)
if not name then break end
if string.sub(name, 1, 1) ~= '(' then locals[name] = {value, tostring(value)} end
i = i + 1
end
i = 1
local ups = {}
while func and true do -- check for func as it may be nil for tail calls
local name, value = debug.getupvalue(func, i)
if not name then break end
ups[name] = {value, tostring(value)}
i = i + 1
end
return locals, ups
end
local stack = {}
for i = (start or 0), 100 do
local source = debug.getinfo(i, "Snl")
if not source then break end
table.insert(stack, {
{source.name, source.source, source.linedefined,
source.currentline, source.what, source.namewhat, source.short_src},
vars(i+1)})
if source.what == 'main' then break end
end
return stack
end

Resources