summaryrefslogtreecommitdiffstats
path: root/doc/wsdg_src/wsdg_lua_support.adoc
diff options
context:
space:
mode:
Diffstat (limited to 'doc/wsdg_src/wsdg_lua_support.adoc')
-rw-r--r--doc/wsdg_src/wsdg_lua_support.adoc436
1 files changed, 436 insertions, 0 deletions
diff --git a/doc/wsdg_src/wsdg_lua_support.adoc b/doc/wsdg_src/wsdg_lua_support.adoc
new file mode 100644
index 00000000..26c3849d
--- /dev/null
+++ b/doc/wsdg_src/wsdg_lua_support.adoc
@@ -0,0 +1,436 @@
+[#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 interpreter which can
+be used to write dissectors, taps, and capture file readers and writers.
+Wireshark versions 4.2.x and earlier support Lua 5.1 and 5.2, and newer
+versions support Lua 5.3 and 5.4. The Lua BitOp library is bundled with
+all version of Wireshark; Lua 5.3 and later also have native support for
+https://www.lua.org/manual/5.4/manual.html#3.4.2[bitwise operators].
+
+If Lua is enabled, Wireshark will first try to load a file named `init.lua`
+from the global link:{wireshark-users-guide-url}ChPluginFolders.html[_plugins directory_].
+and then from the user’s
+link:{wireshark-users-guide-url}ChAppFilesConfigurationSection.html[_personal plugins directory_].
+Then all files ending with _.lua_ are loaded from the global plugins
+directory and its subdirectories. Then all files ending with _.lua_ in the
+personal Lua plugins directory and its subdirectories are loaded. The
+files are processed in ASCIIbetical order (compared byte-by-byte, as `strcmp`),
+descending into each subdirectory depth-first in order.
+
+Whether or not Lua scripts are enabled can be controlled 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.
+
+.Example for init.lua
+[source,lua]
+----
+-- Set enable_lua to false to disable Lua support.
+enable_lua = true
+
+if not enable_lua then
+ return
+end
+
+-- If false and Wireshark was started as (setuid) root, then the user
+-- will not be able to execute custom Lua scripts from the personal
+-- configuration directory, the -Xlua_script command line option or
+-- the Lua Evaluate menu option in the GUI.
+-- Note: Not checked on Windows. running_superuser is always false.
+run_user_scripts_when_superuser = true
+----
+
+The command line option _$$-X lua_script:$$++file.lua++_ can also be used to load
+specific Lua scripts. Arguments can be given to a script loaded at the command
+line with the option _$$-X lua_scriptN:$$++arg++_, where _N_ is the ordinal
+index of the script on the command line. For example, if two scripts were loaded
+on the command line with _$$-X lua_script:$$++my.lua++_ and
+_$$-X lua_script:$$++other.lua++_ in that order, then _$$-X lua_script1:$$++foo++_
+would pass _foo_ to _my.lua_ and _$$-X lua_script2:$$++bar++_ would pass _bar_ to
+_other.lua_. Multiple command line options could be passed to _my.lua_ by
+repeating the option _$$-X lua_script1:$$_. Arguments are available in a script in
+a global table called _arg_, similar to when
+link:https://www.lua.org/manual/5.4/manual.html#7[running Lua standalone].
+
+[IMPORTANT]
+.Loading order matters
+====
+Lua dissectors, unlike <<ChapterDissection,compiled protocol dissectors>>, do
+not have separate <<ChDissectSetup,registration and handoff>> stages yet
+(see wsbuglink:15907[]). Each Lua dissector's registration and handoff is
+completed before moving to the next Lua file in turn.
+That means that the order in which Lua files are read is quite important;
+in order for a Lua dissector to register in a dissector table set up by another
+dissector, the latter dissector must have been already processed. The easiest
+way to ensure this is to put Lua dissectors that need to be registered first
+in files whose name is earlier in ASCIIbetical order (the name of the script
+does not necessarily need to relate to the name of the dissector.)
+
+The Lua code is executed after all compiled dissectors, both built-in and plugin,
+are initialized and before reading any file.
+This means that Lua dissectors can add themselves to tables registered by compiled
+dissectors, but not vice versa; compiled dissectors cannot add themselves to
+dissector tables registered by Lua dissectors.
+====
+
+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)
+----
+
+[#wslua_require_example]
+
+=== Example: Lua scripts with shared modules
+
+Lua plugins that depend on protocols, dissectors, dissector tables, and other
+items registered with Wireshark by other Lua scripts can access those through
+the Wireshark Lua API. The key is ensuring that the providing script is
+read first, as previously mentioned.
+
+It is also possible to depend on Lua functions defined in other Lua scripts.
+The recommended method is to load those scripts as
+link:https://www.lua.org/manual/5.4/manual.html#6.3[modules] via
+link:https://www.lua.org/manual/5.4/manual.html#pdf-require[require].
+Modules preferably should avoid defining globals, and should return a
+table containing functions indexed by name. Globals defined in modules will
+leak into the global namespace when `require()` is used, and name collisions
+can cause unexpected results. (As an aside, local variables are faster in
+Lua because global variables require extra table lookups.) Directories
+containing loaded Lua scripts (including those specified on the command line
+with _$$-X lua_script:$$++my.lua++_) are automatically added to the `require()`
+search path.
+
+For example, suppose there is a Lua script in the personal plugins directory
+named _bar.lua_ as follows:
+
+[source,lua]
+----
+-- bar.lua
+-- Converts an integer representing an IPv4 address into its dotted quad
+-- string representation.
+
+-- This is the module object, which will be returned at the end of this file.
+local M = {
+}
+
+M.GetIPAddressString = function(ip)
+ -- Lua BitOp library, included in all versions of Wireshark
+ --local octet1 = bit.rshift(bit.band(0xFF000000, ip), 24)
+ --local octet2 = bit.rshift(bit.band(0x00FF0000, ip), 16)
+ --local octet3 = bit.rshift(bit.band(0x0000FF00, ip), 8)
+ --local octet4 = bit.band(0x000000FF, ip)
+
+ -- Lua >= 5.3 native bit operators, supported in Wireshark >= 4.4
+ local octet1 = ip >> 24
+ local octet2 = ip >> 16 & 0xFF
+ local octet3 = ip >> 8 & 0xFF
+ local octet4 = ip & 0xFF
+
+ return octet1 .. "." .. octet2 .. "." .. octet3 .. "." .. octet4
+end
+
+-- Return the table we've created, which will be accessible as the return
+-- value of require() or dofile(), and at the global package.loaded["bar"]
+return M
+----
+
+Other Lua plugins that wish to use the module can then `require()` it
+(note that the _.lua_ extension is not used in `require()`, unlike the
+similar `dofile()`):
+
+[source,lua]
+----
+-- Foo dissector
+local p_foo = Proto("foo", "Foo")
+
+local bar = require("bar")
+
+local f_ip = ProtoField.ipv4("foo.ip", "IP")
+local f_ipint = ProtoField.uint32("foo.ipint", "IP as Uint32")
+local f_ipstr = ProtoField.string("foo.ipstr", "IP as String")
+
+p_foo.fields = { f_ip, f_ipint, f_ipstr }
+
+function p_foo.dissector(tvbuf, pktinfo, tree)
+
+ -- Set the protocol column to show this name
+ pktinfo.cols.protocol:set("FooMessage")
+
+ local pktlen = tvbuf:reported_length_remaining()
+
+ local subtree = tree:add(p_foo, tvbuf:range(0,pktlen))
+
+ local child, ipaddr = subtree:add_packet_field(f_ip, tvbuf(8, 4), ENC_BIG_ENDIAN)
+ local child, ipint = subtree:add_packet_field(f_ipint, tvbuf(8, 4), ENC_BIG_ENDIAN)
+
+ -- These two are the same string
+ subtree:add(f_ipstr, tvbuf(8,4), bar.GetIPAddressString(ipint))
+ subtree:add(f_ipstr, tvbuf(8,4), tostring(ipaddr))
+
+ return pktlen
+end
+
+DissectorTable.get("udp.port"):add(2012, p_foo)
+----
+
+Using `require()` is another way to control the order in which files are loaded.
+Lua `require()` ensures that a module is only executed once. Subsequent calls
+will return the same table already loaded.
+
+[IMPORTANT]
+.Avoid duplicate registration
+====
+In versions of Wireshark before 4.4, the initial loading of Lua plugins in the
+plugins directory does not register them in the table of already loaded modules
+used by `require()`. This means that Lua script in the plugins directory that
+are initially loaded can be executed a second time by `require()`. For scripts
+that register dissectors or tables with Wireshark, this will result in errors like
+`Proto new: there cannot be two protocols with the same description`. It is
+safer to `require()` only Lua scripts that define common functions but do not
+call the Wireshark Lua API to register protocols, dissectors, etc.
+
+In 4.4 and later, scripts in the plugin directories are loaded using the same
+internal methods as `require()`, which eliminates duplicate registration errors
+from loading of files in the plugin directory and using `require()`. This also
+means that the order in which plugins are loaded can be adjusted by using
+`require()` in addition to changing file names. However, duplicate registration
+errors can still happen with other methods of executing a file that do
+not check if it has already been loaded, like `dofile()`.
+====
+
+Lua scripts loaded on the command line are sandboxed into their own environment
+and globals defined in them do not leak in the general global environment.
+Modules loaded via `require()` within those scripts can escape that sandboxing,
+however. Plugins in the personal (but not global) directory had similar
+sandboxing prior to Wireshark 4.4, but now globals defined in plugins in the
+personal directory will enter the global namespace for other plugins, as has
+always been the case for plugins in the global plugin directory.
+
+[#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.