Skip to content

Instantly share code, notes, and snippets.

@danielinux
Created September 30, 2016 11:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielinux/d9e854962e88b33ee77d41009fc0497f to your computer and use it in GitHub Desktop.
Save danielinux/d9e854962e88b33ee77d41009fc0497f to your computer and use it in GitHub Desktop.
Dozer utilities
----------------------------------------
-- script-name: dozer.lua
--
-- Based on example LUA dissector by Hadriel Kaplan <hadrielk at yahoo dot com>
-- Copyright (c) 2016 Daniele Lacamera
-- GPLv2
--
-- Wireshark dissector for the VLC implementation of the Dozer protocol
--
-- To add the dissector, start your wireshark using:
-- wireshark -X lua_script:dozer.lua
--
local debug_level = {
DISABLED = 0,
LEVEL_1 = 1,
LEVEL_2 = 2
}
local DEBUG = debug_level.LEVEL_1
local default_settings =
{
debug_level = DEBUG,
port = 1236,
heur_enabled = true,
}
local args={...} -- get passed-in args
if args and #args > 0 then
for _, arg in ipairs(args) do
local name, value = arg:match("(.+)=(.+)")
if name and value then
if tonumber(value) then
value = tonumber(value)
elseif value == "true" or value == "TRUE" then
value = true
elseif value == "false" or value == "FALSE" then
value = false
elseif value == "DISABLED" then
value = debug_level.DISABLED
elseif value == "LEVEL_1" then
value = debug_level.LEVEL_1
elseif value == "LEVEL_2" then
value = debug_level.LEVEL_2
else
error("invalid commandline argument value")
end
else
error("invalid commandline argument syntax")
end
default_settings[name] = value
end
end
local dprint = function() end
local dprint2 = function() end
local function reset_debug_level()
if default_settings.debug_level > debug_level.DISABLED then
dprint = function(...)
print(table.concat({"Lua:", ...}," "))
end
if default_settings.debug_level > debug_level.LEVEL_1 then
dprint2 = dprint
end
end
end
reset_debug_level()
dprint2("Wireshark version = ", get_version())
dprint2("Lua version = ", _VERSION)
local major, minor, micro = get_version():match("(%d+)%.(%d+)%.(%d+)")
if major and tonumber(major) <= 1 and ((tonumber(minor) <= 10) or (tonumber(minor) == 11 and tonumber(micro) < 3)) then
error( "Sorry, but your Wireshark/Tshark version ("..get_version()..") is too old for this script!\n"..
"This script needs Wireshark/Tshark version 1.11.3 or higher.\n" )
end
assert(ProtoExpert.new, "Wireshark does not have the ProtoExpert class, so it's too old - get the latest 1.11.3 or higher")
local dozer = Proto("dozer","Dozer Protocol")
local pf_signature = ProtoField.uint16 ("dozer.signature", "Signature", base.HEX)
local pf_type = ProtoField.uint16 ("dozer.type", "Type", base.HEX)
local pf_seq = ProtoField.uint16 ("dozer.seq", "Sequence")
local pf_win = ProtoField.uint16 ("dozer.win", "Window")
local pf_count = ProtoField.uint16 ("dozer.count", "Counter")
local pf_size = ProtoField.uint16 ("dozer.size", "Payload Size")
local pf_media = ProtoField.string ("dozer.media", "Payload")
dozer.fields = { pf_signature, pf_type, pf_seq, pf_win, pf_count, pf_size, pf_media }
local ef_transport = ProtoExpert.new("dozer.query.expert", "Dozer multimedia transport",
expert.group.REQUEST_CODE, expert.severity.CHAT)
local ef_too_short = ProtoExpert.new("dozer.too_short.expert", "Dozer message too short",
expert.group.MALFORMED, expert.severity.ERROR)
local ef_bad_signature = ProtoExpert.new("dozer.bad_signature.expert", "Dozer: bad packet signature",
expert.group.MALFORMED, expert.severity.ERROR)
dozer.experts = { ef_transport, ef_too_short, ef_bad_signature}
local debug_pref_enum = {
{ 1, "Disabled", debug_level.DISABLED },
{ 2, "Level 1", debug_level.LEVEL_1 },
{ 3, "Level 2", debug_level.LEVEL_2 },
}
dozer.prefs.debug = Pref.enum("Debug", default_settings.debug_level,
"The debug printing level", debug_pref_enum)
dozer.prefs.port = Pref.uint("Port number", default_settings.port,
"The UDP port number for Dozer")
dozer.prefs.heur = Pref.bool("Heuristic enabled", default_settings.heur_enabled,
"Whether heuristic dissection is enabled or not")
function dozer.prefs_changed()
dprint2("prefs_changed called")
default_settings.debug_level = dozer.prefs.debug
reset_debug_level()
default_settings.heur_enabled = dozer.prefs.heur
if default_settings.port ~= dozer.prefs.port then
-- remove old one, if not 0
if default_settings.port ~= 0 then
dprint2("removing Dozer from port",default_settings.port)
DissectorTable.get("udp.port"):remove(default_settings.port, dozer)
end
-- set our new default
default_settings.port = dozer.prefs.port
-- add new one, if not 0
if default_settings.port ~= 0 then
dprint2("adding Dozer to port",default_settings.port)
DissectorTable.get("udp.port"):add(default_settings.port, dozer)
end
end
end
dprint2("Dozer Prefs registered")
function dozer.dissector(tvbuf,pktinfo,root)
dprint2("dozer.dissector called")
-- set the protocol column to show our protocol name
pktinfo.cols.protocol:set("VLC Dozer")
-- We want to check that the packet size is rational during dissection, so let's get the length of the
-- packet buffer (Tvb).
-- Because DNS has no additional payload data other than itself, and it rides on UDP without padding,
-- we can use tvb:len() or tvb:reported_len() here; but I prefer tvb:reported_length_remaining() as it's safer.
local pktlen = tvbuf:reported_length_remaining()
-- We start by adding our protocol to the dissection display tree.
-- A call to tree:add() returns the child created, so we can add more "under" it using that return value.
-- The second argument is how much of the buffer/packet this added tree item covers/represents - in this
-- case (DNS protocol) that's the remainder of the packet.
local tree = root:add(dozer, tvbuf:range(0,12))
local signature = tvbuf:range(0,2):uint()
local ptype = tvbuf:range(2,2):uint()
local pseq = tvbuf:range(4,2):uint()
local pwin = tvbuf:range(6,2):uint()
local pcount = tvbuf:range(8,2):uint()
local psize = tvbuf:range(10,2):uint()
local payload = tvbuf:range(12, pktlen - 12)
if (signature ~= 0xd023) then
tree:add_proto_expert_info(ef_bad_signature)
dprint("packet length",pktlen,"too short")
return
end
-- now let's check it's not too short
if (pktlen - 12) < psize then
-- since we're going to add this protocol to a specific UDP port, we're going to
-- assume packets in this port are our protocol, so the packet being too short is an error
-- the old way: tree:add_expert_info(PI_MALFORMED, PI_ERROR, "packet too short")
-- the correct way now:
tree:add_proto_expert_info(ef_too_short)
dprint("packet length",pktlen,"too short")
return
end
tree:add(pf_signature, signature)
tree:add(pf_type, ptype)
tree:add(pf_seq, pseq)
tree:add(pf_win, pwin)
tree:add(pf_count, pcount)
tree:add(pf_size, psize)
-- now the mp2t part
local mpeg = tree:add(dozer, payload)
if (ptype == 0) then
local post_action = Dissector.get("mp2t")
post_action(payload:tvb(), pktinfo, mpeg)
else if (ptype == 0x1000) then
tree:add(pf_media, "FEC (Row)")
else
tree:add(pf_media, "FEC (Column)")
end
end
-- tell wireshark how much of tvbuff we dissected
return pktlen
end
DissectorTable.get("udp.port"):add(default_settings.port, dozer)
local function heur_dissect_dozer(tvbuf,pktinfo,root)
dprint2("heur_dissect_dozer called")
-- if our preferences tell us not to do this, return false
if not default_settings.heur_enabled then
return false
end
local check = tvbr:range(0,2):uint()
if check ~= 0xd023 then
dprint("heur_dissect_dozer: invalid signature:",check)
return false
end
local check = tvbr:range(2,2):uint()
if check > 2 then
dprint("heur_dissect_dozer: invalid type:",check)
return false
end
-- ok, looks like it's ours, so go dissect it
-- note: calling the dissector directly like this is new in 1.11.3
-- also note that calling a Dissector object, as this does, means we don't
-- get back the return value of the dissector function we created previously
-- so it might be better to just call the function directly instead of doing
-- this, but this script is used for testing and this tests the call() function
dozer.dissector(tvbuf,pktinfo,root)
-- since this is over a transport protocol, such as UDP, we can set the
-- conversation to make it sticky for our dissector, so that all future
-- packets to/from the same address:port pair will just call our dissector
-- function directly instead of this heuristic function
-- this is a new attribute of pinfo in 1.11.3
pktinfo.conversation = dozer
return true
end
dozer:register_heuristic("udp",heur_dissect_dozer)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment