Platform: (where Lua and LuaSocket are ported)
An embedded system using ARM 7 development board running 3rd party RTOS with TCP/IP stack.
What works:
Using Lua standard library such as "io" calls, print, assert, etc
sending UDP packets by using the udp = assert(socket.udp) method, assert(udp:send(something))
Problem:
When executing an example smtp lua script:
local smtp = require("socket.smtp")
from = "myEmail"
rcpt = {"<someOne's Email>"}
mesgt = { heasers = {someHeader}, body = "Hello World" }
r, e = smtp.send {
from = from,
rcpt = rcpt,
source = smtp.message(mesgt),
server = "someServer",
port = 25,
}
-- an error returns after execution:
-- lua\socket\smtp.lua:115: attempt to call field 'try' (a nil value)
-- Corresponding code in smtp.lua around line 115:
function open(server, port, create)
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
TIMEOUT, create))
local s = base.setmetatable({tp = tp}, metat)
-- make sure tp is closed if we get an exception
s.try = socket.newtry(function()
s:close()
end)
return s
end
// Where try = newtry() in socket.lua and the corresponding C code is the same
// from the one provided with the library for UNIX:
static int global_newtry(lua_State *L) {
lua_settop(L, 1);
if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
lua_pushcclosure(L, finalize, 1);
return 1;
}
Well, since the error says that "try is nil", then my best guess is that the C lib is not correctly, or not completely, linked to your Lua. This could be the result of a faulty installation, a missing lib, or something of that sort.
Related
I'm using nvim for Flutter development. From time to time, if I save a file with compilation errors, then the emulator still hotloads it and my PC hangs.
I use a custom key mapping to save my files. I'd like that to call a function which checks that (pseudo code)
if lua vim.lsp.diagnostic.get_count() > 0 echo an error, else do the save
With Neovim LSP diagnostics, you could use this function to get count of diagnostics of each type (error, warning, info, hint) :
get_diag_count = function()
local diagnostics = vim.diagnostic.get(0)
local count = { 0, 0, 0, 0 }
for _, diagnostic in ipairs(diagnostics) do
if vim.startswith(vim.diagnostic.get_namespace(diagnostic.namespace).name, 'vim.lsp') then
count[diagnostic.severity] = count[diagnostic.severity] + 1
end
end
error_count = count[vim.diagnostic.severity.ERROR]
warning_count = count[vim.diagnostic.severity.WARN]
info_count = count[vim.diagnostic.severity.INFO]
hint_count = count[vim.diagnostic.severity.HINT]
return error_count, warning_count, info_count, hint_count
end
What I want to avoid is to capture/ignore the exception when FFI calls a non-existent method.
For example, the following code calls the non_existent_method. However, pcall cannot handle the error.
local ffi = require "ffi"
local C = ffi.C
ffi.cdef [[
int non_existent_method(int num);
]]
local ok, ret = pcall(C.non_existent_method, 1)
if not ok then
return
end
I got the following error with OpenResty/lua-nginx-module.
lua entry thread aborted: runtime error: dlsym(RTLD_DEFAULT, awd): symbol not found
One more apporach would be to call the index metamethod directly:
You might want to wrap that into a function:
local ffi_mt = getmetatable(ffi.C)
function is_valid_ffi_call(sym)
return pcall(ffi_mt.__index, ffi.C, sym)
end
example:
ffi.cdef[[void (*foo)();]]
ffi.cdef[[int puts(const char *);]]
a,func = is_valid_ffi_call("foo")
-- false, "error message: symbol not found or missing declaration, whatever it is"
a,func = is_valid_ffi_call("puts")
-- true, cdata<int ()>: 0x7ff93ad307f0
One possible solution would be wrapping the C.non_existent_method call with a lua function.
For example
local ok, ret = pcall(function()
return C.non_existent_method(len)
end)
if not ok then
......
end
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))
My code are as follow:
local ffi = require "ffi"
local ffi_C = ffi.C
local ffi_typeof = ffi.typeof
local ffi_new = ffi.new
local ffi_string = ffi.string
local NULL = ngx.null
local tostring = tostring
ffi.cdef[[
char * strtok(char * str, const char * delimiters);
]]
local p_char_type = ffi_typeof("char[?]")
function split(src, c)
local result = {}
local pch = ffi_new(p_char_type, 1)
local psrc = ffi_new(p_char_type, #src)
local pc = ffi_new(p_char_type, #c)
ffi.copy(psrc, src)
ffi.copy(pc, c)
pch = ffi_C.strtok(psrc, pc)
while pch do
table.insert(result, ffi_string(pch))
pch = ffi_C.strtok(NULL, pc)
ngx.log(ngx.ERR, "pch ok")
end
ngx.log(ngx.ERR, "split ok")
return result
end
When I run my nginx, there are something wrong happened!
After return by the while loop, the nginx worker process crashed with signal 11.
The last ngx.log can not run.
How can I deal with it?
local psrc = ffi_new(p_char_type, #src)
ffi.copy(psrc, src)
ffi.copy when given a string source also copies a null terminator, but your array is too small to hold it, resulting an overflow.
Also, instead of using strtok, consider using Lua patterns. They are safer, easier to use, and don't depend on the FFI.
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)