Examples in this page need to be updated to the current WSLUA API
dissectors
- Dissectors are meant to analyze some part of a packets data. They are similar to their big brothers written in C. They have to be registered to handle a type of payload of another protocol (or a raw wiretap type). They are passed a buffer (the data) a tree root and a packet information record.
- Like dissectors written in C, Lua dissectors can use Wireshark's ability to reassemble TCP streams:
- To not use TCP reassembly, make your Lua dissector function return nothing (nil) or 0 (in case dissector can't dissect packet).
- To request reassembly via the pinfo struct as described in README.developers, set pinfo.desegment_len and pinfo.desegment_offset (works from Wireshark 1.1.2).
- To request reassembly via return value, return the length of the dissected packet in bytes (positive number) or the number of bytes missing to decode a full packet as a negative number. If you don't know the exact number of needed bytes, return DESEGMENT_ONE_MORE_SEGMENT global "constant" (this is how new-style dissectors requests reassembly in Wireshark).
To be registered they have assigned to a Protocol.
-- trivial protocol example
-- declare our protocol
trivial_proto = Proto("trivial","Trivial Protocol")
-- create a function to dissect it
function trivial_proto.dissector(buffer,pinfo,tree)
pinfo.cols.protocol = "TRIVIAL"
local subtree = tree:add(trivial_proto,buffer(),"Trivial Protocol Data")
subtree:add(buffer(0,2),"The first two bytes: " .. buffer(0,2):uint())
subtree = subtree:add(buffer(2,2),"The next two bytes")
subtree:add(buffer(2,1),"The 3rd byte: " .. buffer(2,1):uint())
subtree:add(buffer(3,1),"The 4th byte: " .. buffer(3,1):uint())
end
-- load the udp.port table
udp_table = DissectorTable.get("udp.port")
-- register our protocol to handle udp port 7777
udp_table:add(7777,trivial_proto)
postdissectors
A postdissector is a dissector registered to be called after every other dissector has been called already. These are handy as all protocol fields are already there so they can be accessed and they can add items to the dissection tree.
-- trivial postdissector example
-- declare some Fields to be read
ip_src_f = Field.new("ip.src")
ip_dst_f = Field.new("ip.dst")
tcp_src_f = Field.new("tcp.srcport")
tcp_dst_f = Field.new("tcp.dstport")
-- declare our (pseudo) protocol
trivial_proto = Proto("trivial","Trivial Postdissector")
-- create the fields for our "protocol"
src_F = ProtoField.string("trivial.src","Source")
dst_F = ProtoField.string("trivial.dst","Destination")
conv_F = ProtoField.string("trivial.conv","Conversation","A Conversation")
-- add the field to the protocol
trivial_proto.fields = {src_F, dst_F, conv_F}
-- create a function to "postdissect" each frame
function trivial_proto.dissector(buffer,pinfo,tree)
-- obtain the current values the protocol fields
local tcp_src = tcp_src_f()
local tcp_dst = tcp_dst_f()
local ip_src = ip_src_f()
local ip_dst = ip_dst_f()
if tcp_src then
local subtree = tree:add(trivial_proto,"Trivial Protocol Data")
local src = tostring(ip_src) .. ":" tostring(tcp_src)
local dst = tostring(ip_dst) .. ":" tostring(tcp_dst)
local conv = src .. "->" .. dst
subtree:add(src_F,src)
subtree:add(dst_F,dst)
subtree:add(conv_F,conv)
end
end
-- register our protocol as a postdissector
register_postdissector(trivial_proto)
chained dissectors
Chaining dissectors similarly allows you to have access to one dissector's data, but doesn't have to run against every packet.
-- works as of Wireshark v0.99.7
do
local http_wrapper_proto = Proto("http_extra", "Extra analysis of the HTTP protocol");
-- (to confirm this worked, check that this protocol appears at the bottom of the "Filter Expression" dialog)
-- our new fields
local F_newfield1 = ProtoField.uint16("http.newfield1", "Our new field, #1", base.DEC)
local F_newfield2 = ProtoField.uint16("http.newfield2", "Our new field, #2", base.DEC)
-- add the fields to the protocol
-- (to confirm this worked, check that these fields appeared in the "Filter Expression" dialog)
http_wrapper_proto.fields = {F_newfield1, F_newfield2} -- NOT ProtoFieldArray, that stopped working a while ago
-- declare the fields we need to read
local f_set_cookie = Field.new("http.set_cookie")
local f_referer = Field.new("http.referer")
local original_http_dissector
function http_wrapper_proto.dissector(tvbuffer, pinfo, treeitem)
-- we've replaced the original http dissector in the dissector table,
-- but we still want the original to run, especially because we need to read its data
original_http_dissector:call(tvbuffer, pinfo, treeitem)
if f_set_cookie() then
-- this has two effects:
-- 1. makes it so we can use "http_extra" as a display filter
-- 2. displays a new header in the tree pane for our protocol
local subtreeitem = treeitem:add(http_wrapper_proto, tvbuffer)
field1_val = 42
subtreeitem:add(F_newfield1, tvbuffer(), field1_val)
:set_text("Don't panic: " .. field1_val)
-- (now "http.newfield1 == 42" should work as a display filter)
field2_val = 616
subtreeitem:add(F_newfield2, tvbuffer(), field2_val)
:set_text("The REAL number of the beast: " .. field2_val)
end
end
local tcp_dissector_table = DissectorTable.get("tcp.port")
original_http_dissector = tcp_dissector_table:get_dissector(80) -- save the original dissector so we can still get to it
tcp_dissector_table:add(80, http_wrapper_proto) -- and take its place in the dissector table
end