Wireshark-users: [Wireshark-users] A Working Lua Tap Example
From: Leonard Nielsen <leonard.nielsen@xxxxxxxxxxxx>
Date: Wed, 1 Nov 2006 08:58:34 -0600
This is my first functional Lua script. Many of the examples on this site
do not work with the current version so I hope this will help others who
want to try Lua. This script creates a CSV file with any HTTP or TDS-RPC
request that takes over x seconds (x is currently set to 20 seconds). I am
using this to identify which MS-SQL stored procedure is causing which web
page to time-out.

The http tap was fairly straight forward but the tds tap is a real hack.
tds_type extractor was returning a "userdata" value instead of an integer
and the TDS dissector does not create fields with the RPC name or
parameters. I need to find out how to access the reassembled PDU with the
tvb function instead of the packet data.

One feature I would like see added to Wireshark's Lua is Unicode string
support. Here is a link to a web page where Lua Unicode support is working
http://www.workspacewhiz.com/Other/LuaState/LuaState.html

Is anyone working on improving the tds dissector? It seems like freetds.org
has all of the information needed to decode the parameters.

Thanks for making Lua available. It really enhances the functionality of
Wireshark.

   --  Lua Response Time Monitor
   --
   --  Logs slow response times for HTTP and MS-SQL RPCs
   --  Turn off TCP reassembly of pdu for the TDS tap

   trigger = 20   -- log requests that take more that trigger seconds
   logfile = "wb"..os.date("%Y%m%d")..".csv"
   io.output(logfile)
   io.write("Timestamp,Protocol,Session,Request,Info,Duration\n")


   -- Define the field extractors that will be used
   ip_addr_extractor = Field.new("ip.addr")
   tcp_port_extractor = Field.new("tcp.port")
   http_request_extractor = Field.new("http.request")
   http_uri_extractor = Field.new("http.request.uri")
   http_method_extractor = Field.new("http.request.method")
   http_code_extractor = Field.new("http.response.code")


   -- HTTP Processing
   http = Tap.new("http","http.request || http.response");
   http_reqs = {} -- outstanding http requests
   http_start = {} -- http request timestamp

   function http.reset()
       http_reqs = {}
       http_start = {}
   end

   function http.packet(pinfo)
      local ip_src, ip_dst = ip_addr_extractor()
      local tcp_src, tcp_dst = tcp_port_extractor()
      local http_request = http_request_extractor()
      local http_method = http_method_extractor()
      local http_uri = http_uri_extractor()
      local http_code = http_code_extractor()
      local conv_key, timestamp

      if http_request then
         conv_key =  tostring(ip_dst) .. ":" .. tostring(tcp_dst) .. " " ..
   tostring(ip_src) .. ":" .. tostring(tcp_src)
         http_reqs[conv_key] = tostring(http_method).."
   "..tostring(http_uri)
         http_start[conv_key] = pinfo.abs_ts
      else
         conv_key =  tostring(ip_src) .. ":" .. tostring(tcp_src) .. " " ..
   tostring(ip_dst) .. ":" .. tostring(tcp_dst)
         if http_reqs[conv_key] then
            if pinfo.abs_ts - http_start[conv_key]>trigger then
               timestamp = os.date("%c",http_start[conv_key]) .. "." ..
   string.sub(tostring(http_start[conv_key] -
   math.floor(http_start[conv_key])),3,5)

   io.write(timestamp,",HTTP,",conv_key,",",http_reqs[conv_key],",",tostring(http_code),",",tostring(pinfo.abs_ts
 - http_start[conv_key]),"\n")
            end
            if tostring(http_code) ~= "100" then
               http_reqs[conv_key] = nil
               http_start[conv_key] = nil
            end
         end
      end
       return true
   end


   -- TDS (MS-SQL RPC) Processing
   tds = Tap.new("tds","tds.type == 0x03 || tds.type == 0x04");
   tds_reqs = {} -- outstanding tds requests
   tds_start = {} -- tds request timestamp

   function tds.reset()
       tds_reqs = {}
       tds_start = {}
   end

   function tds.packet(pinfo,tvb)
      local ip_src, ip_dst = ip_addr_extractor()
      local tcp_src, tcp_dst = tcp_port_extractor()
      local conv_key, timestamp
      local tds_rpclen, tds_rpcname
      local i
      tds_type = tvb(54,1):uint()

      if tds_type == 3 then
         tds_rpclen = 64 + 2 * tvb(62,2):le_uint()
         tds_rpcname = ""
         for i = 64, tds_rpclen, 2 do
            tds_rpcname = tds_rpcname .. tvb(i,1):string()
         end
         conv_key =  tostring(ip_dst) .. ":" .. tostring(tcp_dst) .. " " ..
   tostring(ip_src) .. ":" .. tostring(tcp_src)
         tds_reqs[conv_key] = tds_rpcname
         tds_start[conv_key] = pinfo.abs_ts
      else
         conv_key =  tostring(ip_src) .. ":" .. tostring(tcp_src) .. " " ..
   tostring(ip_dst) .. ":" .. tostring(tcp_dst)
         if tds_reqs[conv_key] then
            if pinfo.abs_ts - tds_start[conv_key]>trigger then
               timestamp = os.date("%c",tds_start[conv_key]) .. "." ..
   string.sub(tostring(tds_start[conv_key] -
   math.floor(tds_start[conv_key])),3,5)

   io.write(timestamp,",TDS,",conv_key,",",tds_reqs[conv_key],",Parms,",tostring(pinfo.abs_ts
 - tds_start[conv_key]),"\n")
            end
            tds_reqs[conv_key] = nil
            tds_start[conv_key] = nil
         end
      end
       return true
   end





******************* PLEASE NOTE *******************
This E-Mail/telefax message and any documents accompanying this
transmission may contain privileged and/or confidential information and is
intended solely for the addressee(s) named above.  If you are not the
intended addressee/recipient, you are hereby notified that any use of,
disclosure, copying, distribution, or reliance on the contents of this
E-Mail/telefax information is strictly prohibited and may result in legal
action against you. Please reply to the sender advising of the error in
transmission and immediately delete/destroy the message and any
accompanying documents.  Thank you.