I have a program which checks for conditions some variable field, like
if(tostring(field) == '0') then {do something}
if(tostring(field) == '1') then {do something}
if(tostring(field) == '2') then {do something}
But, i think lua is interpreting '0' and '1' as TRUE/FALSE values and not checking the corresponding if conditions properly. The condition executes properly for field == '2' condition.
How can i overcome this case? How can i make it work for check conditions '0' and '1'?
Thank You in advance!
In case you are wondering why i tagged wireshark, the if check condition is checking for a field in pcap file.
My lua code for reference is as follows:
#!/usr/bin/lua
do
local pkts = 0
local stat = {}
local file = io.open("luawrite","w")
local function init_listener()
local tap = Listener.new("wlan")
local src_addr = Field.new("wlan.sa")
local type = Field.new("wlan.fc.type")
local sub_type = Field.new("wlan.fc.subtype")
local frame_length = Field.new("frame.len")
local data_rate = Field.new("wlan.data_rate")
function tap.reset()
pkts = 0;
end
function tap.packet(pinfo, tvb)
local client = src_addr()
local stype = sub_type()
local ty = type()
local ts = tostring(pinfo.rel_ts)
local fl = frame_length()
rate = data_rate()
if(tostring(ty) == '0') then
file:write(tostring(ts), "\t", tostring(fl), "\t", tostring(rate), "\n")
end
end
end
init_listener()
end
The condition i am referring to 7th line from last line. If i give the condition tostring(ty) == '2', it works properly.
From the manual:
The condition expression of a control structure can return any value.
Both false and nil are considered false. All values different from nil
and false are considered true (in particular, the number 0 and the
empty string are also true).
Both the number 0 and the empty string evaluate to true, so it's definitely not mistaking the string "0" for false. I might avoid redefining type. Also, I think frame_type returns a number so you can get rid of the tostring() in the condition.
do
local pkts = 0
local stat = {}
local file = io.open("luawrite","w")
local function init_listener()
local tap = Listener.new("wlan")
local src_addr = Field.new("wlan.sa")
-- Changed function from type to frame_type
local frame_type = Field.new("wlan.fc.type")
local sub_type = Field.new("wlan.fc.subtype")
local frame_length = Field.new("frame.len")
local data_rate = Field.new("wlan.data_rate")
function tap.reset()
pkts = 0;
end
function tap.packet(pinfo, tvb)
local client = src_addr()
local stype = sub_type()
local ty = frame_type()
local ts = tostring(pinfo.rel_ts)
local fl = frame_length()
rate = data_rate()
-- skip the tostring
if ty == 0 then
file:write(tostring(ts), "\t", tostring(fl), "\t", tostring(rate), "\n")
end
end
end
init_listener()
end
If all else fails, try writing a line regardless of the frame type and write the frame type with it:
function tap.packet(pinfo, tvb)
local client = src_addr()
local stype = sub_type()
local ty = frame_type()
local ts = tostring(pinfo.rel_ts)
local fl = frame_length()
rate = data_rate()
file:write(tostring(ty), "\t", tostring(ts), "\t", tostring(rate), "\n")
end
Then you can see which frame types you're receiving.
As Corbin said, it's definitely not interpreting "0" and "1" as TRUE/FALSE. Wireshark runs the stock Lua interpreter, and Lua only considers nil and the boolean value of false as false values. Of course you're not really checking if they're false values, you're doing a string comparison of the string-ified value of the "wlan.fc.type" field value to the string "0" or the string "1" or whatever. The actual value you get for the "wlan.fc.type" field is a number, so as Corbin said there's no need to convert it to a string and string-compare it to a string of "0" or whatever... just compare them as numbers.
Regardless, stringifying both of them should have worked too (just been less efficient), so the odds are there simply isn't an 802.11 packet with a wlan.fc.type of 0 in your capture. A wlan.fc.type of 0 is a management frame, a 1 is a control frame, and a 2 is a data frame. So the odds are you're only capturing 802.11 data packets, which is why your comparison of the string-ified wlan.fc.type to the string "2" succeeds.
One way to find out is to open your capture file in wireshark, and put in a display filter for "wlan.fc.type == 0" and see if any packets are shown. If not, then you don't have any management packets.
Related
I want to take a look at all of the options which have been set to some window
current_window = vim.api.nvim_get_current_win()
vim.wo[current_window].wrap = true
Trying just to call print(vim.inspect(current_window)) gives me this:
{
<metatable> = {
__index = <function 1>,
__newindex = <function 2>
}
}
Trying to get size of the table gives me zero:
local v = vim.wo[current_window]
print(#v) -- result is 0
But at the same time this property exists. The next snippet gives me true
print(vim.inspect(vim.wo[current_window].wrap)) -- result is true
How can I extract all of the window options?
Type :h options.txt
Type /local to window and press enter
Press n or N to go forward and backward
Make sure you've read :h help-summary and :h user-manual
Came to the next snippet, which will print out options for the current window in neovim
local all_options = api.nvim_get_all_options_info()
local win_number = api.nvim_get_current_win()
local v = vim.wo[win_number]
local all_options = api.nvim_get_all_options_info()
local result = ""
for key, val in pairs(all_options) do
if val.global_local == false and val.scope == "win" then
result = result .. "|" .. key .. "=" .. tostring(v[key] or "<not set>")
end
end
print(result)
In javascript we can do the following:
var someString = `some ${myVar} string`
I have the following lua code, myVar is a number that needs to be in the square brackets:
splash:evaljs('document.querySelectorAll("a[title*=further]")[myVar]')
Function that fits you description is string.format:
splash:evaljs(string.format('document.querySelectorAll("a[title*=further]")[%s]', myVar))
It is not as verbose as ${}. It is more of a good old (and hated) sprintf.
I have written an emulation of Python's f'' strings, which is a set of functions you can hide inside a require file. So, if you like Python's f'' strings, this may be what you're looking for.
(If anyone finds errors, please notify.)
It's quite big compared to the other solution, but if you hide the bulk in a library, then its use is more compact and readable, IMO.
With this library you can do the following, for example:
require 'f_strings'
a = 12345
print(f'Number: {a}, formatted with two decimals: {a::%.2f}')
-- Number: 12345, formatted with two decimals: 12345.00
Note the use of Lua string.format formatting codes, and the use of double colon (instead of Python's single colon) for format specifiers because of Lua's use of colon for methods.
I have extracted only the relevant functions from a larger library. Although some optimizations may be possible for this specific use case, I leave them unchanged as they are general purpose and may also be useful for other purposes.
And here's the required library (placed somewhere in your Lua libraries folder):
-- f_strings.lua ---
unpack = table.unpack or unpack
--------------------------------------------------------------------------------
-- Escape special pattern characters in string to be treated as simple characters
--------------------------------------------------------------------------------
local
function escape_magic(s)
local MAGIC_CHARS_SET = '[()%%.[^$%]*+%-?]'
if s == nil then return end
return (s:gsub(MAGIC_CHARS_SET,'%%%1'))
end
--------------------------------------------------------------------------------
-- Returns iterator to split string on given delimiter (multi-space by default)
--------------------------------------------------------------------------------
function string:gsplit(delimiter)
if delimiter == nil then return self:gmatch '%S+' end --default delimiter is any number of spaces
if delimiter == '' then return self:gmatch '.' end
if type(delimiter) == 'number' then --break string in equal-size chunks
local index = 1
local ans
return function()
ans = self:sub(index,index+delimiter-1)
if ans ~= '' then
index = index + delimiter
return ans
end
end
end
if self:sub(-#delimiter) ~= delimiter then self = self .. delimiter end
return self:gmatch('(.-)'..escape_magic(delimiter))
end
--------------------------------------------------------------------------------
-- Split a string on the given delimiter (comma by default)
--------------------------------------------------------------------------------
function string:split(delimiter,tabled)
tabled = tabled or false --default is unpacked
local ans = {}
for item in self:gsplit(delimiter) do
ans[#ans+1] = item
end
if tabled then return ans end
return unpack(ans)
end
--------------------------------------------------------------------------------
function copy(t) --returns a simple (shallow) copy of the table
if type(t) == 'table' then
local ans = {}
for k,v in next,t do ans[ k ] = v end
return ans
end
return t
end
--------------------------------------------------------------------------------
function eval(expr,vars)
--evaluate a string expression with optional variables
if expr == nil then return end
vars = vars or {}
assert(type(expr) == 'string','String expected as 1st arg')
assert(type(vars) == 'table','Variable table expected as 2nd arg')
local env = {abs=math.abs,acos=math.acos,asin=math.asin,atan=math.atan,
atan2=math.atan2,ceil=math.ceil,cos=math.cos,cosh=math.cosh,
deg=math.deg,exp=math.exp,floor=math.floor,fmod=math.fmod,
frexp=math.frexp,huge=math.huge,ldexp=math.ldexp,log=math.log,
max=math.max,min=math.min,modf=math.modf,pi=math.pi,pow=math.pow,
rad=math.rad,random=math.random,randomseed=math.randomseed,
sin=math.sin,sinh=math.sinh,sqrt=math.sqrt,tan=math.tan,
tanh=math.tanh}
for name,value in pairs(vars) do env[name] = value end
local a,b = pcall(load('return '..expr,nil,'t',env))
if a == false then return nil,b else return b end
end
--------------------------------------------------------------------------------
-- f'' formatted strings like those introduced in Python v3.6
-- However, you must use Lua style format modifiers as with string.format()
--------------------------------------------------------------------------------
function f(s)
local env = copy(_ENV) --start with all globals
local i,k,v,fmt = 0
repeat
i = i + 1
k,v = debug.getlocal(2,i) --two levels up (1 level is this repeat block)
if k ~= nil then env[k] = v end
until k == nil
local
function go(s)
local fmt
s,fmt = s:sub(2,-2):split('::')
if s:match '%b{}' then s = (s:gsub('%b{}',go)) end
s = eval(s,env)
if fmt ~= nil then
if fmt:match '%b{}' then fmt = eval(fmt:sub(2,-2),env) end
s = fmt:format(s)
end
return s
end
return (s:gsub('%b{}',go))
end
I have created a function that (pseudo)randomly creates a table containing numbers. I then loop this function until at least correct result is found. As soon as I've confirmed that at least one such result exists, I stop the function and return the table.
When I create tables containing small values, there are no issues. However, once the random numbers grow to the range of hundreds, the function begins to return nil, even though the table is true the line before I return it.
local sort = table.sort
local random = math.random
local aMin, aMax = 8, 12
local bMin, bMax = 200, 2000
local function compare( a, b )
return a < b
end
local function getNumbers()
local valid = false
local numbers = {}
-- Generate a random length table, containing random number values.
for i = 1, random( aMin, aMax ) do
numbers[i] = random( bMin, bMax )
end
sort( numbers, compare )
-- See if a specific sequence of numbers exist in the table.
for i = 2, #numbers do
if numbers[i-1]+1 == numbers[i] or numbers[i-1] == numbers[i] then
-- Sequence found, so stop.
valid = true
break
end
end
for i = 1, #numbers-1 do
for j = i+1, #numbers do
if numbers[j] % numbers[i] == 0 and numbers[i] ~= 1 then
valid = true
break
end
end
end
if valid then
print( "Within function:", numbers )
return numbers
else
getNumbers()
end
end
local numbers = getNumbers()
print( "Outside function:", numbers )
This function, to my understanding, is supposed to loop infinitely until I find a valid sequence. The only way that the function can even end, according to my code, is if valid is true.
Sometimes, more often than not, with large numbers the function simply outputs a nil value to the outside of the function. What is going on here?
You're just doing getNumbers() to recurse instead of return getNumbers(). This means that if the recursion gets entered, the final returned value will be nil no matter what else happens.
In the else case of the if valid then, you are not returning anything. You only return anything in the valid case. In the else case, a recursive call may return something, but then you ignore that returned value. The print you see is corresponding to the return from the recursive call; it isn't making it out the original call.
You mean to return getNumbers().
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())
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