Files
blob2wireshark/src/b2ws-plugin/b2ws_snippet.lua

242 lines
10 KiB
Lua

require "b2ws_const"
local loaded_b2ws_util= assert(loadfile(b2ws_const.B2WS_PLUGIN_PATH .. b2ws_const.B2WS_UTIL_FILE))
loaded_b2ws_util()
function b2ws_create_field_object(name, type, type_suffix)
local trim_type = b2ws_trim(type)
local trim_type_suffix = b2ws_trim(type_suffix)
local ws_type_name = b2ws_trim(string.match(trim_type, "(%w+)"))
local size_string = b2ws_trim(string.match(ws_type_name, "(%d+)"))
local bit_size = tonumber(size_string)
local array_number = b2ws_trim(string.match(trim_type_suffix, "%[(.*)%]"))
local bit_mask = nil
if array_number ~= nil then
if array_number == "" then
bit_size = 0
else
local array_number_value = tonumber(array_number)
if array_number_value ~= nil then
bit_size = bit_size * array_number_value
end
end
else
local bit_start, bit_end = string.match(trim_type_suffix, ":(%d+)-(%d+)")
if bit_start ~= nil and bit_end ~= nil then
local bit_start_value = tonumber(bit_start)
local bit_end_value = tonumber(bit_end)
if bit_start ~= nil and bit_end ~= nil then
bit_size = bit_end_value - bit_start_value + 1
bit_mask = 0
for i = bit_start_value,bit_end_value do
bit_mask = bit_mask + 2^i
end
end
end
end
return {["name"] = b2ws_trim(name), ["type"] = ws_type_name, ["bit_size"] = bit_size, ["bit_mask"] = bit_mask, ["array_number"] = array_number}
end
function b2ws_create_struct_object(name)
return {["name"] = b2ws_trim(name), ["size"] = -1, ["fields"] = {}}
end
function b2ws_parse_struct(struct_string)
local struct_name, field_list = string.match(b2ws_trim(struct_string), "struct%s+(%g+)%s*{(.*)}")
struct_object = b2ws_create_struct_object(struct_name)
local tmp_bit_size = 0
for key_index, field_string in next, b2ws_string_split(field_list, ";")
do
local trim_filed_string = b2ws_trim(field_string)
if trim_filed_string ~= "" then
local type_name, field_name, type_suffix = string.match(trim_filed_string, "(%g+)%s+([%w_]+)(%g*)")
if type_suffix == nil then
type_suffix = ""
end
local tmp_field_object = b2ws_create_field_object(field_name, type_name, type_suffix)
struct_object.fields[key_index] = tmp_field_object
tmp_bit_size = tmp_bit_size + tmp_field_object.bit_size
end
end
if tmp_bit_size % 8 ~= 0 then
tmp_bit_size = tmp_bit_size + 8
end
struct_object.size = tmp_bit_size / 8
return struct_object
end
next_proto_template = [[-- {field_name} Layer
{field_name}_layer = Proto("{field_name}_layer", "{field_name} layer")
function {field_name}_layer.dissector(buffer, packet_info, tree)
{field_name}_layer_tree = tree:add({field_name}_layer, buffer(0, buffer:len()))
end
]]
next_proto_dissector_call = [[Dissector.get("{field_name}_layer"):call(buffer({struct_size}, buffer:len() - {struct_size}):tvb(), packet_info, {struct_name}_layer_tree)]]
proto_template = [[-- {struct_name} Layer
{struct_name}_layer = Proto("{struct_name}_layer", "{struct_name} layer")
local {struct_name}_layer_fields = {struct_name}_layer.fields
{field_declarations}
function {struct_name}_layer.dissector(buffer, packet_info, tree)
{struct_name}_layer_tree = tree:add({struct_name}_layer, buffer(0, {struct_size}))
{field_definitions}
end]]
field_declaration_template = [===[{struct_name}_layer_fields.{field_name} = ProtoField.{field_type}("{struct_name}_layer_fields.{field_name}", "{field_name}", {base_type}, nil--[[valuestring]], {bit_mask}, "{field_name} description")]===]
field_definition_template = [[
local {field_name}_value = buffer(current_offset, {field_end}):{to_method}()
{struct_name}_layer_tree:add({struct_name}_layer_fields.{field_name}, buffer(current_offset, {field_end}), {field_name}_value)
current_offset = current_offset + {field_end}]]
first_field_definition_template = [[
local {field_name}_value = buffer(0, {field_end}):{to_method}()
{struct_name}_layer_tree:add({struct_name}_layer_fields.{field_name}, buffer(0, {field_end}), {field_name}_value)
local current_offset = {field_end}]]
last_field_definition_template = [[
local {field_name}_value = buffer(current_offset, {field_end}):{to_method}()
{struct_name}_layer_tree:add({struct_name}_layer_fields.{field_name}, buffer(current_offset, {field_end}), {field_name}_value)]]
pad_lef_template = "0x%0{pad_count}x"
function b2ws_create_dissector_next_layer_snippet(field_object, template_string)
return template_string:gsub("{field_name}", field_object.name)
end
function b2ws_create_dissector_call_snippet(struct_object, field_object, template_string)
local result_template = template_string:gsub("{field_name}", field_object.name)
result_template = result_template:gsub("{struct_name}", struct_object.name)
return result_template:gsub("{struct_size}", struct_object.size)
end
function b2ws_create_dissector_fields_definition_snippet(struct_object, field_object, template_string)
local result_template = template_string:gsub("{struct_name}", struct_object.name)
local array_number = field_object.array_number
if array_number== nil then
result_template = result_template:gsub("{to_method}", "le_uint")
else
result_template = result_template:gsub("local {field_name}_value = buffer%(current_offset, {field_end}%):{to_method}%(%)\n","")
result_template = result_template:gsub("local {field_name}_value = %g+\n", "")
result_template = result_template:gsub(", {field_name}_value%)", ")")
end
result_template = result_template:gsub("{field_name}", field_object.name)
local bit_size = field_object.bit_size
if bit_size == 0 then
result_template = result_template:gsub("{field_end}", "buffer:len() - current_offset")
else
if bit_size % 8 ~= 0 then
bit_size = bit_size + 8
end
local byte_size = bit_size / 8
if array_number == nil or tonumber(array_number) ~= nil then
if field_object.bit_mask ~= nil then
byte_size = tonumber(string.match(field_object.type, "(%d+)")) / 8
result_template = result_template:gsub("\ncurrent_offset = current_offset %+ {field_end}", "")
result_template = result_template:gsub("local current_offset = {field_end}", "local current_offset = 0")
end
result_template = result_template:gsub("{field_end}", string.match(byte_size, "(%d+)"))
else
result_template = result_template:gsub("{field_end}", string.match(byte_size, "(%d+)") .. " * " .. array_number .. "_value")
end
end
return result_template
end
function b2ws_create_dissector_fields_declaration_snippet(struct_object, field_object, template_string)
local result_template = template_string:gsub("{struct_name}", struct_object.name)
result_template = result_template:gsub("{field_name}", field_object.name)
local field_type = field_object.type
if field_object.array_number == nil then
result_template = result_template:gsub("{field_type}", field_type)
else
result_template = result_template:gsub("{field_type}", "bytes")
end
if field_object.array_number ~= nil then
result_template = result_template:gsub("{base_type}", "base.NONE")
elseif b2ws_string_starts(field_type, "u") then
result_template = result_template:gsub("{base_type}", "base.HEX")
else
result_template = result_template:gsub("{base_type}", "base.DEC")
end
local bit_mask = field_object.bit_mask
if bit_mask == nil then
bit_mask = "nil"
else
local size_string = string.match(field_type, "(%d+)")
local bit_size = string.match(tonumber(size_string) / 4, "(%d+)")
bit_mask = string.format( pad_lef_template:gsub("{pad_count}", bit_size), bit_mask)
end
return result_template:gsub("{bit_mask}", bit_mask)
end
function get_fields_definition_template(field_object)
if field_object.bit_mask ~= nil then
return value
end
end
function b2ws_create_dissector_fields_snippet(struct_object, template_string)
local field_list = struct_object.fields
local field_declarations_string = ""
local field_definitions_string = "\n"
local tmp_bit_size = 0
local field_list_len = #field_list
local field_object = nil
local tmp_field_definition_template = first_field_definition_template
if field_list_len > 1 then
field_object = field_list[1]
field_declarations_string = field_declarations_string .. b2ws_create_dissector_fields_declaration_snippet(struct_object, field_object, field_declaration_template) .. "\n"
field_definitions_string = field_definitions_string .. b2ws_create_dissector_fields_definition_snippet(struct_object, field_object, tmp_field_definition_template) .. "\n"
tmp_field_definition_template = field_definition_template
if field_list_len > 2 then
for key_index = 2, field_list_len - 1
do
field_object = field_list[key_index]
field_declarations_string = field_declarations_string .. b2ws_create_dissector_fields_declaration_snippet(struct_object, field_object, field_declaration_template) .. "\n"
field_definitions_string = field_definitions_string .. b2ws_create_dissector_fields_definition_snippet(struct_object, field_object, tmp_field_definition_template) .. "\n"
end
end
end
local pre_template = ""
field_object = field_list[field_list_len]
if field_object.bit_size == 0 then
pre_template = b2ws_create_dissector_next_layer_snippet(field_object, next_proto_template) .. "\n"
field_definitions_string = field_definitions_string .. b2ws_create_dissector_call_snippet(struct_object, field_object, next_proto_dissector_call)
else
field_declarations_string = field_declarations_string .. b2ws_create_dissector_fields_declaration_snippet(struct_object, field_object, field_declaration_template).. "\n"
field_definitions_string = field_definitions_string .. b2ws_create_dissector_fields_definition_snippet(struct_object, field_object, last_field_definition_template)
end
local result_template_string = template_string:gsub("{field_declarations}", field_declarations_string)
result_template_string = result_template_string:gsub("{field_definitions}", field_definitions_string:gsub("\n", "\n\t"))
return pre_template .. result_template_string
end
function b2ws_create_dissector_layer_snippet(struct_object, template_string)
local result_template = template_string:gsub("{struct_name}", struct_object.name)
if struct_object.fields[#struct_object.fields].bit_size == 0 then
result_template = result_template:gsub("{struct_size}", "buffer:len()")
end
return result_template:gsub("{struct_size}", struct_object.size)
end
function b2ws_create_dissector_snippet(struct_object)
local result_template = b2ws_create_dissector_fields_snippet(struct_object, proto_template)
return b2ws_create_dissector_layer_snippet(struct_object, result_template)
end