forked from osmocom/wireshark
260 lines
8.4 KiB
Plaintext
260 lines
8.4 KiB
Plaintext
[#wsluarm]
|
||
|
||
// Attributes
|
||
:build_dir: .
|
||
|
||
== Lua Support in Wireshark
|
||
|
||
[#wsluarm_intro]
|
||
|
||
=== Introduction
|
||
|
||
Lua is a powerful light-weight programming language designed for extending
|
||
applications. Wireshark contains an embedded Lua 5.2 interpreter which
|
||
can be used to write dissectors, taps, and capture file readers
|
||
and writers.
|
||
|
||
Wireshark’s Lua interpreter starts by loading a file named `init.lua` from
|
||
Wireshark's link:{wireshark-users-guide-url}ChAppFilesConfigurationSection.html[_global configuration directory_].
|
||
The _global configuration directory_'s `init.lua` controls whether or not Lua
|
||
scripts are enabled via the
|
||
_$$enable_lua$$_ variable. Lua scripts are enabled by
|
||
default. To disable Lua scripts, set the _$$enable_lua$$_ variable to _false_.
|
||
Wireshark 2.6 and earlier enabled or disabled Lua scripts using
|
||
the variable _$$disable_lua$$_ (deprecated). If both _$$enable_lua$$_ and
|
||
_$$disable_lua$$_ are present, _$$disable_lua$$_ is ignored.
|
||
|
||
If Lua is enabled, Wireshark will try to load a file named `init.lua`
|
||
from the user’s
|
||
link:{wireshark-users-guide-url}ChAppFilesConfigurationSection.html[_personal configuration directory_]
|
||
and all files ending with _.lua_ in the global and the personal
|
||
link:{wireshark-users-guide-url}ChPluginFolders.html[_plugins directory_].
|
||
|
||
The command line option _$$-X lua_script:$$++file.lua++_ can also be used to load
|
||
specific Lua scripts.
|
||
|
||
The Lua code is executed after all protocol dissectors are
|
||
initialized and before reading any file.
|
||
|
||
Wireshark for Windows uses a modified Lua runtime
|
||
(link:https://github.com/Lekensteyn/lua-unicode[lua-unicode]) to
|
||
support Unicode (UTF-8) filesystem paths. This brings consistency with other
|
||
platforms (for example, Linux and macOS).
|
||
|
||
[#wslua_menu_example]
|
||
|
||
=== Example: Creating a Menu with Lua
|
||
|
||
The code below adds a menu "Lua Dialog Test" under the Tools menu.
|
||
When selected, it opens a dialog prompting the user for input
|
||
and then opens a text window with the output.
|
||
|
||
[source,lua]
|
||
----
|
||
|
||
-- Define the menu entry's callback
|
||
local function dialog_menu()
|
||
local function dialog_func(person,eyes,hair)
|
||
local window = TextWindow.new("Person Info");
|
||
local message = string.format("Person %s with %s eyes and %s hair.", person, eyes, hair);
|
||
window:set(message);
|
||
end
|
||
|
||
new_dialog("Dialog Test",dialog_func,"A Person","Eyes","Hair")
|
||
end
|
||
|
||
-- Create the menu entry
|
||
register_menu("Lua Dialog Test",dialog_menu,MENU_TOOLS_UNSORTED)
|
||
|
||
-- Notify the user that the menu was created
|
||
if gui_enabled() then
|
||
local splash = TextWindow.new("Hello!");
|
||
splash:set("Wireshark has been enhanced with a useless feature.\n")
|
||
splash:append("Go to 'Tools->Lua Dialog Test' and check it out!")
|
||
end
|
||
|
||
----
|
||
|
||
[#wslua_dissector_example]
|
||
|
||
=== Example: Dissector written in Lua
|
||
|
||
[source,lua]
|
||
----
|
||
local p_multi = Proto("multi", "MultiProto");
|
||
|
||
local vs_protos = {
|
||
[2] = "mtp2",
|
||
[3] = "mtp3",
|
||
[4] = "alcap",
|
||
[5] = "h248",
|
||
[6] = "ranap",
|
||
[7] = "rnsap",
|
||
[8] = "nbap"
|
||
}
|
||
|
||
local f_proto = ProtoField.uint8("multi.protocol", "Protocol", base.DEC, vs_protos)
|
||
local f_dir = ProtoField.uint8("multi.direction", "Direction", base.DEC, { [1] = "incoming", [0] = "outgoing"})
|
||
local f_text = ProtoField.string("multi.text", "Text")
|
||
|
||
p_multi.fields = { f_proto, f_dir, f_text }
|
||
|
||
local data_dis = Dissector.get("data")
|
||
|
||
local protos = {
|
||
[2] = Dissector.get("mtp2"),
|
||
[3] = Dissector.get("mtp3"),
|
||
[4] = Dissector.get("alcap"),
|
||
[5] = Dissector.get("h248"),
|
||
[6] = Dissector.get("ranap"),
|
||
[7] = Dissector.get("rnsap"),
|
||
[8] = Dissector.get("nbap"),
|
||
[9] = Dissector.get("rrc"),
|
||
[10] = DissectorTable.get("sctp.ppi"):get_dissector(3), -- m3ua
|
||
[11] = DissectorTable.get("ip.proto"):get_dissector(132), -- sctp
|
||
}
|
||
|
||
function p_multi.dissector(buf, pkt, tree)
|
||
|
||
local subtree = tree:add(p_multi, buf(0,2))
|
||
subtree:add(f_proto, buf(0,1))
|
||
subtree:add(f_dir, buf(1,1))
|
||
|
||
local proto_id = buf(0,1):uint()
|
||
|
||
local dissector = protos[proto_id]
|
||
|
||
if dissector ~= nil then
|
||
-- Dissector was found, invoke subdissector with a new Tvb,
|
||
-- created from the current buffer (skipping first two bytes).
|
||
dissector:call(buf(2):tvb(), pkt, tree)
|
||
elseif proto_id < 2 then
|
||
subtree:add(f_text, buf(2))
|
||
-- pkt.cols.info:set(buf(2, buf:len() - 3):string())
|
||
else
|
||
-- fallback dissector that just shows the raw data.
|
||
data_dis:call(buf(2):tvb(), pkt, tree)
|
||
end
|
||
|
||
end
|
||
|
||
local wtap_encap_table = DissectorTable.get("wtap_encap")
|
||
local udp_encap_table = DissectorTable.get("udp.port")
|
||
|
||
wtap_encap_table:add(wtap.USER15, p_multi)
|
||
wtap_encap_table:add(wtap.USER12, p_multi)
|
||
udp_encap_table:add(7555, p_multi)
|
||
----
|
||
|
||
[#wslua_tap_example]
|
||
|
||
=== Example: Listener written in Lua
|
||
|
||
[source,lua]
|
||
----
|
||
-- This program will register a menu that will open a window with a count of occurrences
|
||
-- of every address in the capture
|
||
|
||
local function menuable_tap()
|
||
-- Declare the window we will use
|
||
local tw = TextWindow.new("Address Counter")
|
||
|
||
-- This will contain a hash of counters of appearances of a certain address
|
||
local ips = {}
|
||
|
||
-- this is our tap
|
||
local tap = Listener.new();
|
||
|
||
local function remove()
|
||
-- this way we remove the listener that otherwise will remain running indefinitely
|
||
tap:remove();
|
||
end
|
||
|
||
-- we tell the window to call the remove() function when closed
|
||
tw:set_atclose(remove)
|
||
|
||
-- this function will be called once for each packet
|
||
function tap.packet(pinfo,tvb)
|
||
local src = ips[tostring(pinfo.src)] or 0
|
||
local dst = ips[tostring(pinfo.dst)] or 0
|
||
|
||
ips[tostring(pinfo.src)] = src + 1
|
||
ips[tostring(pinfo.dst)] = dst + 1
|
||
end
|
||
|
||
-- this function will be called once every few seconds to update our window
|
||
function tap.draw(t)
|
||
tw:clear()
|
||
for ip,num in pairs(ips) do
|
||
tw:append(ip .. "\t" .. num .. "\n");
|
||
end
|
||
end
|
||
|
||
-- this function will be called whenever a reset is needed
|
||
-- e.g. when reloading the capture file
|
||
function tap.reset()
|
||
tw:clear()
|
||
ips = {}
|
||
end
|
||
|
||
-- Ensure that all existing packets are processed.
|
||
retap_packets()
|
||
end
|
||
|
||
-- using this function we register our function
|
||
-- to be called when the user selects the Tools->Test->Packets menu
|
||
register_menu("Test/Packets", menuable_tap, MENU_TOOLS_UNSORTED)
|
||
----
|
||
|
||
[#wsluarm_modules]
|
||
|
||
== Wireshark’s Lua API Reference Manual
|
||
|
||
This Part of the User Guide describes the Wireshark specific functions in the embedded Lua.
|
||
|
||
Classes group certain functionality, the following notational conventions are
|
||
used:
|
||
|
||
* _Class.function()_ represents a class method (named _function_) on class
|
||
_Class_, taking no arguments.
|
||
|
||
* _Class.function(a)_ represents a class method taking one argument.
|
||
|
||
* _Class.function(...)_ represents a class method taking a variable number of
|
||
arguments.
|
||
|
||
* _class:method()_ represents an instance method (named _method_) on an instance
|
||
of class _Class_, taking no arguments. Note the lowercase notation in the
|
||
documentation to clarify an instance.
|
||
|
||
* _class.prop_ represents a property _prop_ on the instance of class _Class_.
|
||
|
||
Trying to access a non-existing property, function or method currently gives an
|
||
error, but do not rely on it as the behavior may change in the future.
|
||
|
||
|
||
include::{build_dir}/wsluarm_src/wslua_utility.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_gui.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_proto.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_field.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_pinfo.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_tvb.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_tree.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_listener.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_dumper.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_wtap.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_file.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_dir.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_int64.adoc[]
|
||
include::{build_dir}/wsluarm_src/wslua_struct.adoc[]
|
||
|
||
[#lua_module_PCRE2]
|
||
|
||
=== PCRE2 Regular Expressions
|
||
|
||
Lua has its own native _pattern_ syntax in the string library, but sometimes a
|
||
real regex engine is more useful. Wireshark comes with Perl Compatible Regular
|
||
Expressions version 2 (PCRE2). This engine is exposed into Wireshark’s Lua engine through the
|
||
well-known Lrexlib library. The module is loaded in the global environment using
|
||
the "rex_pcre2" table. The manual is available at https://rrthomas.github.io/lrexlib/manual.html.
|