Lua - custom dissector for Wireshark

An example implementation of Wireshark dissector written in Lua can be found here. This should be a nice template for people trying to decode/analyse protocols that are not recognized normally by Wireshark. The code should be easy enough to understand.

The full code is a bit larger but I needed a dissector for SNTP and it is quite small so I can copy it here:

-- ---------------------------- --
-- Simple Network Time Protocol --
-- ---------------------------- --
-- https://tools.ietf.org/html/rfc4330




sntp_proto = Proto("SNTP","Simple Network Time Protocol")

local sntp_proto_li = {
  [0] = "no warning",
  [1] = "last minute has 61 seconds",
  [2] = "last minute has 59 seconds",
  [3] = "alarm condition (clock not synchronized)",
}

local sntp_proto_mode = {
  [0] = "reserved",
  [1] = "symmetric active",
  [2] = "symmetric passive",
  [3] = "client",
  [4] = "server",
  [5] = "broadcast",
  [6] = "reserved for NTP control message",
  [7] = "reserved for private use",
}

local sf = sntp_proto.fields
sf.li = ProtoField.uint8("sntp.li","leap indicator",base.DEC,sntp_proto_li,0xC0)
sf.vn = ProtoField.uint8("sntp.vn","Version",base.DEC,nil,0x38)
sf.mode = ProtoField.uint8("sntp.mode","mode",base.DEC,sntp_proto_mode,0x07)
sf.stratum = ProtoField.uint8("sntp.stratum","stratum",base.DEC)
sf.poll = ProtoField.uint8("sntp.poll","poll",base.HEX)
sf.precis = ProtoField.int8("sntp.precision","precision",base.DEC)
sf.rootdelay = ProtoField.uint32("sntp.root_delay","root delay",base.DEC)
sf.rootdispe = ProtoField.uint32("sntp.root_dispersion","root dispersion",base.DEC)
sf.refid = ProtoField.uint32("sntp.ref_id","reference id",base.HEX)
sf.refts = ProtoField.uint64("sntp.ref_ts","reference timestamp",base.HEX)
sf.orgts = ProtoField.uint64("sntp.org_ts","originate timestamp",base.HEX)
sf.rxts = ProtoField.uint64("sntp.tx_ts","receive timestamp",base.HEX)
sf.txts = ProtoField.uint64("sntp.rx_ts","transmit timestamp",base.HEX)

function sntp_proto.dissector(buf,pinfo,tree)
  local subtree = tree:add(sntp_proto,buf(),"Simple Network Time Protocol")
  subtree:add(sf.li,buf(0,1))
  subtree:add(sf.vn,buf(0,1))
  subtree:add(sf.mode,buf(0,1))
  subtree:add(sf.stratum,buf(1,1))
  subtree:add(sf.poll,buf(2,1))
  subtree:add(sf.precis,buf(3,1))
  subtree:add(sf.rootdelay,buf(4,4))
  subtree:add(sf.rootdispe,buf(8,4))
  subtree:add(sf.refid,buf(12,4))
  subtree:add(sf.refts,buf(16,8))
  subtree:add(sf.orgts,buf(24,8))
  subtree:add(sf.rxts,buf(32,8))
  subtree:add(sf.txts,buf(40,8))
end


In my case I'm using this dissector as a "subdissector" for a different protocol. The main dissector is attached to a specific ether type value at the end of the file.

The biggest problem with writing a dissector, at least for the layer2 protocols IMHO, is to know where to "connect it" into the dissectors already present in Wireshark. A partial list of known places to which you can connect your dissector can be generated from the Wireshark source code, using this command:

grep -R register_dissector_table * | \
perl -pe 's/^.+register_dissector_table.+?\"(.+?)\".*/$1/' | \
sort -u

Or a much easier way (as pointed out in the comments, thanks :)) since sometime Wireshark has a special menu that shows the dissector tables. I have no idea how did I miss that :).



1 comment:

  1. Anonymous2/7/12 14:19

    The Wireshark GUI lists the dissector tables. Go to menu "Internal > Dissector tables".

    Plus, it's spelled "Lua" (not "LUA").

    Otherwise, great post. I commend you for usage of local variables. Most people create globals haphazardly.

    ReplyDelete