Add Wireshark dissector.
parent
837eae2da6
commit
a102f08855
@ -0,0 +1,306 @@
|
|||||||
|
-- Copyright (c) 2010, Robert G. Jakabosky <bobby@sharedrealm.com> All rights reserved.
|
||||||
|
|
||||||
|
-- cache globals to local for speed.
|
||||||
|
local format=string.format
|
||||||
|
local tostring=tostring
|
||||||
|
local tonumber=tonumber
|
||||||
|
local sqrt=math.sqrt
|
||||||
|
local pairs=pairs
|
||||||
|
|
||||||
|
-- wireshark API globals
|
||||||
|
local Pref = Pref
|
||||||
|
local Proto = Proto
|
||||||
|
local ProtoField = ProtoField
|
||||||
|
local DissectorTable = DissectorTable
|
||||||
|
local ByteArray = ByteArray
|
||||||
|
local PI_MALFORMED = PI_MALFORMED
|
||||||
|
local PI_ERROR = PI_ERROR
|
||||||
|
|
||||||
|
-- zmq protocol example
|
||||||
|
-- declare our protocol
|
||||||
|
local zmq_proto = Proto("zmq","ZMQ","ZeroMQ Protocol")
|
||||||
|
|
||||||
|
-- setup preferences
|
||||||
|
zmq_proto.prefs["tcp_port_start"] =
|
||||||
|
Pref.string("TCP port range start", "5555", "First TCP port to decode as this protocol")
|
||||||
|
zmq_proto.prefs["tcp_port_end"] =
|
||||||
|
Pref.string("TCP port range end", "5555", "Last TCP port to decode as this protocol")
|
||||||
|
-- current preferences settings.
|
||||||
|
local current_settings = {
|
||||||
|
tcp_port_start = -1,
|
||||||
|
tcp_port_end = -1,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- setup protocol fields.
|
||||||
|
zmq_proto.fields = {}
|
||||||
|
local fds = zmq_proto.fields
|
||||||
|
fds.frame = ProtoField.new("Frame", "zmq.frame", "FT_BYTES", nil, "BASE_NONE")
|
||||||
|
fds.length = ProtoField.new("Frame Length", "zmq.frame.len", "FT_UINT64", nil, "BASE_DEC")
|
||||||
|
fds.length8 = ProtoField.new("Frame 8bit Length", "zmq.frame.len8", "FT_UINT8", nil, "BASE_DEC")
|
||||||
|
fds.length64 = ProtoField.new("Frame 64bit Length", "zmq.frame.len64", "FT_UINT64", nil, "BASE_DEC")
|
||||||
|
fds.flags = ProtoField.new("Frame Flags", "zmq.frame.flags", "FT_UINT8", nil, "BASE_HEX", "0xFF")
|
||||||
|
fds.flags_more = ProtoField.new("More", "zmq.frame.flags.more", "FT_UINT8", nil, "BASE_HEX", "0x01")
|
||||||
|
fds.body = ProtoField.new("Frame body", "zmq.frame.body", "FT_BYTES", nil, "BASE_NONE")
|
||||||
|
|
||||||
|
-- un-register zmq to handle tcp port range
|
||||||
|
local function unregister_tcp_port_range(start_port, end_port)
|
||||||
|
if not start_port or start_port <= 0 or not end_port or end_port <= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local tcp_port_table = DissectorTable.get("tcp.port")
|
||||||
|
for port = start_port,end_port do
|
||||||
|
tcp_port_table:remove(port,zmq_proto)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- register zmq to handle tcp port range
|
||||||
|
local function register_tcp_port_range(start_port, end_port)
|
||||||
|
if not start_port or start_port <= 0 or not end_port or end_port <= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local tcp_port_table = DissectorTable.get("tcp.port")
|
||||||
|
for port = start_port,end_port do
|
||||||
|
tcp_port_table:add(port,zmq_proto)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle preferences changes.
|
||||||
|
function zmq_proto.init(arg1, arg2)
|
||||||
|
local old_start, old_end
|
||||||
|
local new_start, new_end
|
||||||
|
-- check if preferences have changed.
|
||||||
|
for pref_name,old_v in pairs(current_settings) do
|
||||||
|
local new_v = zmq_proto.prefs[pref_name]
|
||||||
|
if new_v ~= old_v then
|
||||||
|
if pref_name == "tcp_port_start" then
|
||||||
|
old_start = old_v
|
||||||
|
new_start = new_v
|
||||||
|
elseif pref_name == "tcp_port_end" then
|
||||||
|
old_end = old_v
|
||||||
|
new_end = new_v
|
||||||
|
end
|
||||||
|
-- save new value.
|
||||||
|
current_settings[pref_name] = new_v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- un-register old port range
|
||||||
|
if old_start and old_end then
|
||||||
|
unregister_tcp_port_range(tonumber(old_start), tonumber(old_end))
|
||||||
|
end
|
||||||
|
-- register new port range.
|
||||||
|
if new_start and new_end then
|
||||||
|
register_tcp_port_range(tonumber(new_start), tonumber(new_end))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- parse flag bits.
|
||||||
|
local BITS = {
|
||||||
|
MORE = 0x01,
|
||||||
|
RESERVED = 0x7E,
|
||||||
|
}
|
||||||
|
local flag_names = {"MORE"}
|
||||||
|
local bits_lookup = {}
|
||||||
|
local bits_list = {
|
||||||
|
{},
|
||||||
|
{MORE = true},
|
||||||
|
{MORE = true, RESERVED = true},
|
||||||
|
{RESERVED = true},
|
||||||
|
}
|
||||||
|
local function parse_flags(flags)
|
||||||
|
return bits_lookup[flags] or bits_lookup[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- make bits object
|
||||||
|
local function make_bits(bits)
|
||||||
|
local proxy = newproxy(true)
|
||||||
|
local meta = getmetatable(proxy)
|
||||||
|
meta.__index = bits
|
||||||
|
meta.__tostring = function()
|
||||||
|
return bits.flags
|
||||||
|
end
|
||||||
|
-- combind bits into string description.
|
||||||
|
local flags = nil
|
||||||
|
for i=1,#flag_names do
|
||||||
|
local name = flag_names[i]
|
||||||
|
if bits[name] then
|
||||||
|
if flags then
|
||||||
|
flags = flags .. ',' .. name
|
||||||
|
else
|
||||||
|
flags = name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- combind bits into one byte value.
|
||||||
|
local byte = 0x00
|
||||||
|
for k,v in pairs(bits) do
|
||||||
|
local bit = assert(BITS[k], "Invalid bit name.")
|
||||||
|
byte = byte + BITS[k]
|
||||||
|
end
|
||||||
|
bits.flags = flags or ''
|
||||||
|
bits.byte = byte
|
||||||
|
return proxy
|
||||||
|
end
|
||||||
|
-- make bits objects in bis_lookup
|
||||||
|
for i=1,#bits_list do
|
||||||
|
local bits = bits_list[i]
|
||||||
|
bits = make_bits(bits)
|
||||||
|
bits_lookup[bits.byte] = bits
|
||||||
|
end
|
||||||
|
|
||||||
|
local function zmq_dissect_frame(buffer, pinfo, frame_tree, tap)
|
||||||
|
local rang,offset
|
||||||
|
-- Frame length
|
||||||
|
offset = 0
|
||||||
|
local len_off = offset
|
||||||
|
local len8_rang = buffer(offset,1)
|
||||||
|
local len_rang = len8_rang
|
||||||
|
local frame_len = len8_rang:uint()
|
||||||
|
-- 8bit length field
|
||||||
|
local ti = frame_tree:add(fds.length8, len8_rang)
|
||||||
|
ti:set_hidden()
|
||||||
|
offset = offset + 1
|
||||||
|
if frame_len == 255 then
|
||||||
|
local len64_rang = buffer(offset, 8)
|
||||||
|
len_rang = buffer(len_off, 9)
|
||||||
|
frame_len = tonumber(tostring(len64_rang:uint64()))
|
||||||
|
-- 64bit length field.
|
||||||
|
local ti = frame_tree:add(fds.length64, len64_rang)
|
||||||
|
ti:set_hidden()
|
||||||
|
offset = offset + 8
|
||||||
|
local ti = frame_tree:add(fds.length, len_rang)
|
||||||
|
ti:set_text(format("Frame Length: %d", frame_length))
|
||||||
|
else
|
||||||
|
frame_tree:add(fds.length, len_rang)
|
||||||
|
end
|
||||||
|
-- Frame flags
|
||||||
|
rang = buffer(offset,1)
|
||||||
|
local flags = rang:uint()
|
||||||
|
local flags_bits = parse_flags(flags)
|
||||||
|
local flags_list = flags_bits.flags
|
||||||
|
local flags_tree = frame_tree:add(fds.flags, rang)
|
||||||
|
flags_tree:set_text(format('Flags: 0x%02X (%s)', flags, flags_list))
|
||||||
|
flags_tree:add(fds.flags_more, rang)
|
||||||
|
offset = offset + 1
|
||||||
|
if flags_bits.MORE then
|
||||||
|
tap.more = tap.more + 1
|
||||||
|
else
|
||||||
|
-- if the 'more' flag is not set then this is the last frame in a message.
|
||||||
|
tap.msgs = tap.msgs + 1
|
||||||
|
end
|
||||||
|
-- Frame body
|
||||||
|
local body_len = frame_len - 1
|
||||||
|
local body = ''
|
||||||
|
if body_len > 0 then
|
||||||
|
tap.body_bytes = tap.body_bytes + body_len
|
||||||
|
rang = buffer(offset, body_len)
|
||||||
|
local ti = frame_tree:add_le(fds.body, rang)
|
||||||
|
if body_len <= 4 then
|
||||||
|
body = format("%08x", rang:uint())
|
||||||
|
else
|
||||||
|
body = tostring(rang)
|
||||||
|
end
|
||||||
|
ti:set_text(format("%s", body))
|
||||||
|
end
|
||||||
|
offset = offset + body_len
|
||||||
|
-- frame summary
|
||||||
|
if body_len > 0 then
|
||||||
|
if flags_bits.MORE then
|
||||||
|
frame_tree:set_text(format("Frame: [MORE] Body[%u]=%s", body_len, body))
|
||||||
|
else
|
||||||
|
frame_tree:set_text(format("Frame: Body[%u]=%s", body_len, body))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if flags_bits.MORE then
|
||||||
|
frame_tree:set_text(format("Frame: [MORE] No data"))
|
||||||
|
else
|
||||||
|
frame_tree:set_text(format("Frame: No data"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local DESEGMENT_ONE_MORE_SEGMENT = 0x0fffffff
|
||||||
|
local DESEGMENT_UNTIL_FIN = 0x0ffffffe
|
||||||
|
|
||||||
|
-- packet dissector
|
||||||
|
function zmq_proto.dissector(tvb,pinfo,tree)
|
||||||
|
local offset = 0
|
||||||
|
local tvb_length = tvb:len()
|
||||||
|
local reported_length = tvb:reported_len()
|
||||||
|
local length_remaining
|
||||||
|
local zmq_tree
|
||||||
|
local rang
|
||||||
|
local frames = 0
|
||||||
|
local tap = {}
|
||||||
|
|
||||||
|
tap.frames = 0
|
||||||
|
tap.msgs = 0
|
||||||
|
tap.more = 0
|
||||||
|
tap.body_bytes = 0
|
||||||
|
|
||||||
|
while(offset < reported_length and offset < tvb_length) do
|
||||||
|
length_remaining = tvb_length - offset
|
||||||
|
-- check for fixed part of PDU
|
||||||
|
if length_remaining < 2 then
|
||||||
|
pinfo.desegment_offset = offset
|
||||||
|
pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
|
||||||
|
break
|
||||||
|
end
|
||||||
|
-- decode frame length
|
||||||
|
-- decode single byte frame length
|
||||||
|
rang = tvb(offset, 1)
|
||||||
|
local frame_len = rang:le_uint()
|
||||||
|
local pdu_len = frame_len + 1
|
||||||
|
if frame_len == 255 then
|
||||||
|
-- make sure there is enough bytes
|
||||||
|
if length_remaining < 10 then
|
||||||
|
pinfo.desegment_offset = offset
|
||||||
|
pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
|
||||||
|
break
|
||||||
|
end
|
||||||
|
-- decode extra long frame length.
|
||||||
|
rang = tvb(offset + 1, 8)
|
||||||
|
frame_len = tonumber(tostring(rang:uint64()))
|
||||||
|
pdu_len = frame_len + 9
|
||||||
|
end
|
||||||
|
-- provide hints to tcp
|
||||||
|
if not pinfo.visited then
|
||||||
|
local remaining_bytes = reported_length - offset
|
||||||
|
if pdu_len > remaining_bytes then
|
||||||
|
pinfo.want_pdu_tracking = 2
|
||||||
|
pinfo.bytes_until_next_pdu = pdu_len - remaining_bytes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- check if we need more bytes to dissect this frame.
|
||||||
|
if length_remaining < pdu_len then
|
||||||
|
pinfo.desegment_offset = offset
|
||||||
|
pinfo.desegment_len = (pdu_len - length_remaining)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
-- dissect zmq frame
|
||||||
|
if not zmq_tree then
|
||||||
|
zmq_tree = tree:add(zmq_proto,tvb(),"ZMQ frames")
|
||||||
|
end
|
||||||
|
rang = tvb(offset, pdu_len)
|
||||||
|
local frame_tree = zmq_tree:add(fds.frame, rang)
|
||||||
|
zmq_dissect_frame(rang:tvb(), pinfo, frame_tree, tap)
|
||||||
|
frames = frames + 1
|
||||||
|
-- step to next frame.
|
||||||
|
local offset_before = offset
|
||||||
|
offset = offset + pdu_len
|
||||||
|
if offset < offset_before then break end
|
||||||
|
end
|
||||||
|
if zmq_tree then
|
||||||
|
zmq_tree:set_text(format("ZMQ frames=%u", frames))
|
||||||
|
end
|
||||||
|
if frames > 0 then
|
||||||
|
tap.frames = frames
|
||||||
|
pinfo.tap_data = tap
|
||||||
|
end
|
||||||
|
-- Info column
|
||||||
|
pinfo.cols.protocol = "ZMQ"
|
||||||
|
pinfo.cols.info = format('ZMQ frames=%u',frames)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- register zmq to handle tcp ports 5550-5560
|
||||||
|
register_tcp_port_range(5550,5560)
|
||||||
|
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
-- register all zmq taps.
|
||||||
|
require"zmq.ws.stats_tap"
|
||||||
|
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
local tap = require"zmq.ws.tap"
|
||||||
|
|
||||||
|
local format = string.format
|
||||||
|
|
||||||
|
local stats_tap_mt = {}
|
||||||
|
stats_tap_mt.__index = stats_tap_mt
|
||||||
|
|
||||||
|
function stats_tap_mt:packet(pinfo, tvb, tree, data)
|
||||||
|
-- count all ZeroMQ packets
|
||||||
|
self.count = self.count + 1
|
||||||
|
data = data or pinfo.tap_data
|
||||||
|
if not data then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- frames
|
||||||
|
self.frames = self.frames + (data.frames or 0)
|
||||||
|
-- frames with more flag set
|
||||||
|
self.more = self.more + (data.more or 0)
|
||||||
|
-- whole messages.
|
||||||
|
self.msgs = self.msgs + (data.msgs or 0)
|
||||||
|
-- total bytes in frame bodies.
|
||||||
|
self.body_bytes = self.body_bytes + (data.body_bytes or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function stats_tap_mt:draw()
|
||||||
|
return format([[
|
||||||
|
ZeroMQ Packets: %d
|
||||||
|
Frames: %d
|
||||||
|
Messages: %d
|
||||||
|
Flags: More: %d
|
||||||
|
Payload bytes: %d
|
||||||
|
]],
|
||||||
|
self.count,
|
||||||
|
self.frames,
|
||||||
|
self.msgs,
|
||||||
|
self.more,
|
||||||
|
self.body_bytes)
|
||||||
|
end
|
||||||
|
|
||||||
|
function stats_tap_mt:reset()
|
||||||
|
self.count = 0
|
||||||
|
self.frames = 0
|
||||||
|
self.msgs = 0
|
||||||
|
self.more = 0
|
||||||
|
self.body_bytes = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local function create_stats_tap()
|
||||||
|
local tap = setmetatable({}, stats_tap_mt)
|
||||||
|
|
||||||
|
tap:reset() -- initialize tap.
|
||||||
|
return tap, 'zmq', 'lua'
|
||||||
|
end
|
||||||
|
|
||||||
|
tap("ZeroMQ stats tap", create_stats_tap)
|
||||||
|
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
|
||||||
|
local gui_enabled = gui_enabled
|
||||||
|
local register_menu = register_menu
|
||||||
|
local MENU_TOOLS_UNSORTED = MENU_TOOLS_UNSORTED
|
||||||
|
|
||||||
|
local win_instances = 0
|
||||||
|
|
||||||
|
local function create_window_tap(name, create)
|
||||||
|
win_instances = win_instances + 1
|
||||||
|
|
||||||
|
local td, tap_filter, tap_type = create()
|
||||||
|
|
||||||
|
-- tap's output window.
|
||||||
|
local win = TextWindow.new(name .. " " .. win_instances)
|
||||||
|
|
||||||
|
-- this tap will be local to the menu_function that called it
|
||||||
|
local tap = Listener.new(tap_type, tap_filter)
|
||||||
|
|
||||||
|
-- callback to remove the tap when the text window closes
|
||||||
|
function remove_tap()
|
||||||
|
if tap and tap.remove then
|
||||||
|
tap:remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- make sure the tap doesn't hang around after the window was closed
|
||||||
|
win:set_atclose(remove_tap)
|
||||||
|
|
||||||
|
-- this function will be called for every packet
|
||||||
|
function tap.packet(pinfo,tvb, tree, tapdata)
|
||||||
|
return td:packet(pinfo, tvb, tree, tapdata)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- this function will be called once every few seconds to redraw the window
|
||||||
|
function tap.draw()
|
||||||
|
local text = td:draw()
|
||||||
|
win:set(text)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- this function will be called at the end of the capture run.
|
||||||
|
function tap.reset()
|
||||||
|
return td:reset()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function create_tshark_tap(name, create)
|
||||||
|
|
||||||
|
local td, tap_filter, tap_type = create()
|
||||||
|
|
||||||
|
-- this tap will be local to the menu_function that called it
|
||||||
|
local tap = Listener.new(tap_type, tap_filter)
|
||||||
|
|
||||||
|
-- this function will be called for every packet
|
||||||
|
function tap.packet(pinfo,tvb,tapdata)
|
||||||
|
return td:packet(pinfo, tvb, tapdata)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- this function will be called once every few seconds to redraw the window
|
||||||
|
function tap.draw()
|
||||||
|
local text = td:draw()
|
||||||
|
debug(name .. " results:\n" .. text)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- this function will be called at the end of the capture run.
|
||||||
|
function tap.reset()
|
||||||
|
return td:reset()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return function (name, create)
|
||||||
|
if gui_enabled() then
|
||||||
|
-- menu callback.
|
||||||
|
local create_tap = function()
|
||||||
|
create_window_tap(name, create)
|
||||||
|
end
|
||||||
|
-- register menu item if running from wireshark
|
||||||
|
register_menu(name, create_tap, MENU_TOOLS_UNSORTED)
|
||||||
|
else
|
||||||
|
-- we are running from tshark, create a non-gui tap now.
|
||||||
|
create_tshark_tap(name, create)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
Loading…
Reference in New Issue