Lua/Dissectors

Dissectors

TCP reassembly

You should not write a dissector for TCP payload if you cannot handle reassembly (i.e., don't add your Proto object to the DissectorTable for tcp). Like dissectors written in C, Lua dissectors can use Wireshark's ability to reassemble TCP streams:

Examples

   1 -- trivial protocol example
   2 -- declare our protocol
   3 trivial_proto = Proto("trivial","Trivial Protocol")
   4 -- create a function to dissect it
   5 function trivial_proto.dissector(buffer,pinfo,tree)
   6     pinfo.cols.protocol = "TRIVIAL"
   7     local subtree = tree:add(trivial_proto,buffer(),"Trivial Protocol Data")
   8     subtree:add(buffer(0,2),"The first two bytes: " .. buffer(0,2):uint())
   9     subtree = subtree:add(buffer(2,2),"The next two bytes")
  10     subtree:add(buffer(2,1),"The 3rd byte: " .. buffer(2,1):uint())
  11     subtree:add(buffer(3,1),"The 4th byte: " .. buffer(3,1):uint())
  12 end
  13 -- load the udp.port table
  14 udp_table = DissectorTable.get("udp.port")
  15 -- register our protocol to handle udp port 7777
  16 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.

   1 -- trivial postdissector example
   2 -- declare some Fields to be read
   3 ip_src_f = Field.new("ip.src")
   4 ip_dst_f = Field.new("ip.dst")
   5 tcp_src_f = Field.new("tcp.srcport")
   6 tcp_dst_f = Field.new("tcp.dstport")
   7 -- declare our (pseudo) protocol
   8 trivial_proto = Proto("trivial","Trivial Postdissector")
   9 -- create the fields for our "protocol"
  10 src_F = ProtoField.string("trivial.src","Source")
  11 dst_F = ProtoField.string("trivial.dst","Destination")
  12 conv_F = ProtoField.string("trivial.conv","Conversation","A Conversation")
  13 -- add the field to the protocol
  14 trivial_proto.fields = {src_F, dst_F, conv_F}
  15 -- create a function to "postdissect" each frame
  16 function trivial_proto.dissector(buffer,pinfo,tree)
  17     -- obtain the current values the protocol fields
  18     local tcp_src = tcp_src_f()
  19     local tcp_dst = tcp_dst_f()
  20     local ip_src = ip_src_f()
  21     local ip_dst = ip_dst_f()
  22     if tcp_src then
  23        local subtree = tree:add(trivial_proto,"Trivial Protocol Data")
  24        local src = tostring(ip_src) .. ":" .. tostring(tcp_src)
  25        local dst = tostring(ip_dst) .. ":" .. tostring(tcp_dst)
  26        local conv = src  .. "->" .. dst
  27        subtree:add(src_F,src)
  28        subtree:add(dst_F,dst)
  29        subtree:add(conv_F,conv)
  30     end
  31 end
  32 -- register our protocol as a postdissector
  33 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.

   1 -- works as of Wireshark v0.99.7
   2 do
   3         local http_wrapper_proto = Proto("http_extra", "Extra analysis of the HTTP protocol");
   4         -- (to confirm this worked, check that this protocol appears at the bottom of the "Filter Expression" dialog)
   5         -- our new fields
   6         local F_newfield1 = ProtoField.uint16("http.newfield1", "Our new field, #1", base.DEC)
   7         local F_newfield2 = ProtoField.uint16("http.newfield2", "Our new field, #2", base.DEC)
   8         -- add the fields to the protocol
   9         -- (to confirm this worked, check that these fields appeared in the "Filter Expression" dialog)
  10         http_wrapper_proto.fields = {F_newfield1, F_newfield2}          -- NOT ProtoFieldArray, that stopped working a while ago
  11         -- declare the fields we need to read
  12         local f_set_cookie = Field.new("http.set_cookie")
  13         local f_referer    = Field.new("http.referer")
  14         local original_http_dissector
  15         function http_wrapper_proto.dissector(tvbuffer, pinfo, treeitem)
  16                 -- we've replaced the original http dissector in the dissector table,
  17                 -- but we still want the original to run, especially because we need to read its data
  18                 original_http_dissector:call(tvbuffer, pinfo, treeitem)
  19                 if f_set_cookie() then
  20                         -- this has two effects:
  21                         --      1. makes it so we can use "http_extra" as a display filter
  22                         --      2. displays a new header in the tree pane for our protocol
  23                         local subtreeitem = treeitem:add(http_wrapper_proto, tvbuffer)
  24                         field1_val = 42
  25                         subtreeitem:add(F_newfield1, tvbuffer(), field1_val)
  26                                    :set_text("Don't panic: " .. field1_val)
  27                         -- (now "http.newfield1 == 42" should work as a display filter)
  28                         field2_val = 616
  29                         subtreeitem:add(F_newfield2, tvbuffer(), field2_val)
  30                                    :set_text("The REAL number of the beast: " .. field2_val)
  31                 end
  32         end
  33         local tcp_dissector_table = DissectorTable.get("tcp.port")
  34         original_http_dissector = tcp_dissector_table:get_dissector(80) -- save the original dissector so we can still get to it
  35         tcp_dissector_table:add(80, http_wrapper_proto)                 -- and take its place in the dissector table
  36 end

Imported from https://wiki.wireshark.org/Lua/Dissectors on 2020-08-11 23:16:08 UTC