|
local my_pattrib = { |
|
abbr = "my_nbns", |
|
description = "My NetBIOS Name Service", |
|
protocol = "NBNS/MyNBNS", |
|
header_size = 12, |
|
base_protocol = "udp", |
|
dissector_table_name = "port", |
|
port = 137, |
|
vendor = "SonyMobi" |
|
} |
|
|
|
local function make_filter_name(protocol_prefix, field_name) |
|
return protocol_prefix.."."..field_name |
|
end |
|
|
|
local my_proto = Proto(my_pattrib.abbr, my_pattrib.description) |
|
|
|
my_proto.fields = {} |
|
|
|
local flags_responses = { |
|
[0] = "Message is a query", |
|
[1] = "Message is a response" |
|
} |
|
|
|
local flags_opcodes = { |
|
[0x0] = "Name query" |
|
} |
|
|
|
local flags_authoritatives= { |
|
[1] = "Server is an authority for domain" |
|
} |
|
|
|
local flags_truncated = { |
|
[0] = "Message is not truncated" |
|
} |
|
|
|
local flags_recursionDesired = { |
|
[0] = "Don't do query recursively", |
|
[1] = "Do query recursively" |
|
} |
|
|
|
local flags_recursionAvailable = { |
|
[0] = "Server can't do recursive queries", |
|
[1] = "Server can do recursive queries" |
|
} |
|
|
|
local flags_broadcast = { |
|
[0] = "Not a broadcast packet", |
|
[1] = "Broadcast packet" |
|
} |
|
|
|
local falags_replyCode = { |
|
[0x0] = "No error", |
|
[0x3] = "Requested name does not exist" |
|
} |
|
|
|
local my_proto_flags = { |
|
-- ProtoField.new(name, abbr, type, [valuestring], [base], [mask], [descr]) |
|
-- treeitem:add([protofield], [tvbrange] = buffer(offset, size), [value], [label]) |
|
{name = "Response", abbr = "flags_response", type = ftypes.UINT16, offset = 15, size = 1, base = base.HEX, valuestring = flags_responses, mask = 0x8000}, |
|
{name = "Opcode", abbr = "flags_opcode", type = ftypes.UINT16, offset = 14, size = 4, base = base.HEX, valuestring = flags_opcodes, mask = 0x7800}, |
|
{name = "Authoritative", abbr = "flags_authoritative", type = ftypes.UINT16, offset = 10, size = 1, base = base.HEX, valuestring = flags_authoritatives, mask = 0x0400}, |
|
{name = "Truncated", abbr = "flags_truncated", type = ftypes.UINT16, offset = 9, size = 1, base = base.HEX, valuestring = flags_truncated, mask = 0x0200}, |
|
{name = "Recursion desired", abbr = "flags_recursionDesired",type = ftypes.UINT16, offset = 8, size = 1, base = base.HEX, valuestring = flags_recursionDesired, mask = 0x0100}, |
|
{name = "Recursion available", abbr = "flags_recursionAvailable",type = ftypes.UINT16, offset = 7, size = 1, base = base.HEX, valuestring = flags_recursionAvailable, mask = 0x0080}, |
|
{name = "Broadcast", abbr = "flags_broadcast", type = ftypes.UINT16, offset = 4, size = 1, base = base.HEX, valuestring = flags_broadcast, mask = 0x0010}, |
|
{name = "Reply code", abbr = "flags_replyCode", type = ftypes.UINT16, offset = 3, size = 4, base = base.HEX, valuestring = falags_replyCode, mask = 0x000F} |
|
} |
|
|
|
|
|
local my_proto_fields = { |
|
-- ProtoField.new(name, abbr, type, [valuestring], [base], [mask], [descr]) |
|
-- treeitem:add([protofield], [tvbrange] = buffer(offset, size), [value], [label]) |
|
{name = "Transaction ID", abbr = "transaction_id", type = ftypes.UINT16, offset = 0, size = 2, base = base.HEX}, |
|
{name = "Flags", abbr = "flags", type = ftypes.UINT16, offset = 2, size = 2, base = base.HEX, flags = my_proto_flags}, |
|
{name = "Questions", abbr = "questions", type = ftypes.UINT16, offset = 4, size = 2, base = base.DEC}, |
|
{name = "Answer RRs", abbr = "answer_rrs", type = ftypes.UINT16, offset = 6, size = 2, base = base.DEC}, |
|
{name = "Authority RRs", abbr = "authority_rrs", type = ftypes.UINT16, offset = 8, size = 2, base = base.DEC}, |
|
{name = "Additional RRs", abbr = "additional_rrs", type = ftypes.UINT16, offset = 10, size = 2, base = base.DEC} |
|
} |
|
|
|
|
|
for index, fattrib in pairs(my_proto_fields) do |
|
-- ProtoField.new(name, abbr, type, [valuestring], [base], [mask], [descr]) |
|
my_proto.fields[fattrib.abbr] = ProtoField.new(fattrib.name, my_pattrib.abbr.."."..fattrib.abbr, fattrib.type, fattrib.valuestring, fattrib.base, fattrib.mask) |
|
|
|
if fattrib.flags ~= nil then |
|
for index2, fattrib2 in pairs(fattrib.flags) do |
|
-- ProtoField.new(name, abbr, type, [valuestring], [base], [mask], [descr]) |
|
my_proto.fields[fattrib2.abbr] = ProtoField.new(fattrib2.name, my_pattrib.abbr.."."..fattrib2.abbr, fattrib2.type, fattrib2.valuestring, fattrib2.base, fattrib2.mask) |
|
end |
|
end |
|
end |
|
|
|
-- nil after load other capture files if local. |
|
original_proto_dissector = nil |
|
|
|
local function heuristic_checker(buffer, pinfo, tree) |
|
-- guard for port |
|
if (pinfo.src_port ~= my_pattrib.port) and (pinfo.dst_port ~= my_pattrib.port) then |
|
return false |
|
end |
|
|
|
-- guard for length |
|
length = buffer:len() |
|
if length < my_pattrib.header_size then |
|
return false |
|
end |
|
|
|
-- call original dissector. |
|
-- nil afetr "Reload lua plugins" |
|
if original_proto_dissector ~= nil then |
|
original_proto_dissector:call(buffer, pinfo, tree) |
|
end |
|
|
|
-- guard for vendor |
|
local vendor_src = tostring(pinfo.dl_src) |
|
local vendor_dst = tostring(pinfo.dl_dst) |
|
if (vendor_src:find(my_pattrib.vendor) ~= 1) and (vendor_dst:find(my_pattrib.vendor) ~= 1) then |
|
return false |
|
end |
|
|
|
-- both original and this dissector share same buffer, then call this dissector and seek buffer. |
|
my_proto.dissector(buffer, pinfo, tree) |
|
return true |
|
end |
|
|
|
function my_proto.dissector(buffer, pinfo, tree) |
|
pinfo.cols.protocol = my_pattrib.protocol |
|
|
|
local subtree = tree:add(my_proto, buffer(), my_pattrib.description) |
|
|
|
for index, fattrib in pairs(my_proto_fields) do |
|
-- treeitem:add([protofield], [tvbrange] = buffer(offset, size), [value], [label]) |
|
local tvbrange = buffer(fattrib.offset, fattrib.size) |
|
local item = subtree:add(my_proto.fields[fattrib.abbr], tvbrange) |
|
|
|
if fattrib.flags ~= nil then |
|
for index2, fattrib2 in pairs(fattrib.flags) do |
|
-- treeitem:add([protofield], [tvbrange] = buffer(offset, size), [value], [label]) |
|
item:add(my_proto.fields[fattrib2.abbr], tvbrange) |
|
end |
|
end |
|
end |
|
|
|
return |
|
end |
|
|
|
-- register as "heuristic" dissector |
|
my_proto:register_heuristic(my_pattrib.base_protocol, heuristic_checker) |
|
|
|
function my_proto.init() |
|
dissector_table_name = make_filter_name(my_pattrib.base_protocol, my_pattrib.dissector_table_name) |
|
local dissector_table = DissectorTable.get(dissector_table_name) |
|
if (dissector_table == nil) then |
|
return |
|
end |
|
|
|
-- chain dissector |
|
if original_proto_dissector == nil then |
|
original_proto_dissector = dissector_table:get_dissector(my_pattrib.port) |
|
|
|
-- nil afetr "Reload lua plugins" |
|
if original_proto_dissector ~= nil then |
|
-- remove the original dissector so that the "heuristic" dissector can be called |
|
-- even if "Try heuristic sub-dissectors first" preference disabled. |
|
dissector_table:remove(my_pattrib.port, original_proto_dissector) |
|
end |
|
end |
|
end |
My NBNS is developed as the "heuristic" and "chain" one for leaning LuaAPI.
Filtering by device vendor; Alternative protocol tree