Introduction
In Wireshark Lua, there are two types of packet processors: dissectors and listeners.
called for each frame that occurs at a particular dissector table (e.g., UDP port 5000) | called for each frame that matches a particular display filter |
used to parse raw frame data into human-friendly named fields | useful for extracting information from a capture file (including the named fields) |
can be invoked multiple times per frame | invoked only once per frame |
optionally adds protocol fields as tree items (in the Packet Details Pane) | cannot add protocol fields |
There are also post-dissectors:
- a special type of Dissector that is called for every frame and runs after all other non-post-dissectors
- useful for adding tree items that assist in traffic analysis (e.g., using an expert-info tree item to flag high traffic volume between two endpoints)
- example post-dissector
How to write a Lua dissector
Create a Lua file (named proto_foo.lua
) at one of the following directories:
C:\Program Files\Wireshark\plugins\1.6.8\
(Windows)C:\Users\johndoe\AppData\Roaming\Wireshark\plugins\
(Windows)$HOME/.wireshark/plugins/
(UN*X)
In proto_foo.lua
, do the following:
- Declare the protocol with
Proto()
. - Declare the protocol's fields with
ProtoField.XXX()
. - (OPTIONAL) Declare the protocol's preferences with
Pref.XXX()
. - Declare the protocol's
dissector(Tvb, Pinfo, TreeItem)
function (called for each frame). - (OPTIONAL) Declare the protocol's
init()
function (called whenever prefs are set or a pcap is loaded) - Register the protocol with a
DissectorTable
(inside init()
if it exists).
See example implementation of proto_foo.lua
Start tshark
or Wireshark
. If the Lua script contained any syntax errors, an error message appears, and you'll have to edit the file and restart the program.
To quickly verify whether Foo was properly registered, enter foo
in Wireshark's Display Filter Textbox, and confirm that it turns green.
To test your Foo dissector, start a Wireshark capture session, and generate traffic on the corresponding network interface. If using the example implementation of Foo, you can use netcat to generate a 21-byte UDP payload on port 3456 (assumes default network interface):
$ echo "123456789012345678901" | nc -w 1 -u 1.1.1.1 3456
How to write a Lua listener
Create a Lua file (named tap_foo.lua
) at one of the following directories:
C:\Program Files\Wireshark\plugins\1.6.8\
(Windows)C:\Users\johndoe\AppData\Roaming\Wireshark\plugins\
(Windows)$HOME/.wireshark/plugins/
(UN*X)
In tap_foo.lua
, do the following:
Declare the tap with the Listener(BuiltInTapName, DisplayFilter)
function. You can use one of the built-in taps or create a new one that uses the specified display filter. The names of the built-in taps are: ip
, udp
, http
, bacapp
, h225
, actrace
, ansi_a
, ansi_map
, eth
, tcp
, wlan
, frame
(OPTIONAL) Declare field extractors (with the Field.new(FieldName)
function) to pull values of named fields from the current packet. These cannot be declared inside the packet function.
Declare the tap's packet(Pinfo, Tvb, BuiltInTapData)
function. This function is notified with every packet that matches the tap's filter. The function is passed the packet info (pinfo
), buffer (Tvb
), and built-in tap data (only if a built-in tap was specified during tap declaration). For better performance, avoid any calls that would cause GUI repainting (e.g., adding items to a listview) in this function; reserve those for the draw function.
(OPTIONAL) Declare the tap's draw()
function. This function is called periodically to notify any external GUI programs to draw the results (which were accumulated in the packet function). This is where you would do any fancy GUI stuff with Wireshark's GUI calls or with, e.g., wxWidgets (via wxLua) or Qt (via lqt).
(OPTIONAL) Declare the tap's reset()
function. This function is called at the beginning and end of a capture run, where any initialization should be done if necessary to prepare for a new session. If your tap doesn't have any local state, then you don't need to implement this function.
See example implementation of tap_foo.lua
(requires proto_foo.lua
above).
Start tshark
or Wireshark
. If the Lua script contained any syntax errors, an error message appears, and you'll have to edit the file and restart the program.
To test your Foo listener, start a Wireshark capture session, and generate traffic on the corresponding network interface. Alternatively, open a pcap
file that contains packets of interest. If using the example implementation of Foo, you can use tshark
as follows:
$ tshark -q -r foo.pcap -R foo
This opens the file foo.pcap
and filters for Foo packets. Assuming tap_foo.lua
exists in one of the directories from Step 1, tshark
automatically loads the listener, which processes the foo
packets from foo.pcap
. The example listener prints the value(s) of a specific field for each packet, so you can easily confirm that from the Wireshark Lua console (Tools > Lua > Console).
Loading a Lua script
There are actually multiple ways to load a Wireshark Lua script. In the steps above, we used Option 2 described below (mostly because it's convenient).
Option 1: Use -Xlua_script:filename
You can use the -X
command-line parameter, specifying lua_script
as the variable name and the path to the script as the variable value. For example, the following command loads the Lua script foo.lua
from the current directory. Note that path can be relative or absolute, and the filename does not need to have the .lua extension.
$ wireshark -X lua_script:foo.lua
Option 2: Put the Lua script in the Lua initialization path
You can put the Lua file in one of the directories that Wireshark/TShark scans at startup, and restart Wireshark/TShark.
UN*X
/share/wireshark/plugins/foo.lua
(global)$HOME/.wireshark/plugins/foo.lua
(user-specific)
Windows
%PROGRAMFILES%\Wireshark\plugins\%WIRESHARK_VERSION%\foo.lua
(global)%APPDATA%\Roaming\Wireshark\plugins\foo.lua
(user-specific)
Option 3: Modify init.lua
to load the file
You can edit the global init.lua
or the user-specific $HOME/.wireshark/init.lua
.
For example, add the following to the end of init.lua
:
-- load the Foo module
dofile('/path/to/foo.lua')
This method allows the highest control during initialization (in case you need to control the load order); and allows putting the Lua files anywhere in the system. However, these files must not be in the Lua initialization path (where they'd automatically be loaded) or else you may encounter a registration error (e.g., from registering a protocol dissector with the same name twice).
Debugging a Lua script
It's mostly a trial-and-error process: You edit the Lua script, load it in Wireshark/TShark, and troubleshoot any errors with print-outs or with Lua debug
. The print-outs can be seen either from the Lua console in Wireshark (Tools > Lua > Console) or from the terminal that started Wireshark/TShark.
The Lua debug
library provides an API that can be helpful. WSLua actually hides the debug
symbol (likely unintentionally) with its own debug()
function that prints to the Lua console (or stdout) at the DEBUG
level. However, you can still access Lua debug
by using the require
keyword:
local d = require 'debug'
– print our traceback (like a stacktrace)
print(d.traceback())
– enter the Lua debugger, which has this prompt: lua_debug>
– (to exit, type 'cont')
d.debug()
answered 05 Jun ‘12, 14:51
helloworld
3.1k●4●20●41
accept rate: 28%
I don't have enough uninterrupted time to formulate a decent answer, but I'll get back to you later. I hope someone beats me to it though. :)
O.K. I'm looking forward to it.
BTW: Who has implemented the Lua integration?
I'm not sure I understand the context of "Lua integration". Are you asking who originally implemented the Wireshark Lua bindings? I believe it was Luis Ontanon and Ulf Lamping.
Yes I mean the Lua binding.
beat/bump ;-)