如何在Lua dissector中向子树添加变长int/float/string数组字段
解决Wireshark Lua Dissector动态变长数组解析问题
核心思路
不用预先创建与数组元素数量匹配的ProtoField,而是复用单个通用字段或直接动态指定解析类型,循环解析每个元素时自定义显示名称,以此适配未知长度的统一类型数组。
实现步骤与代码示例
1. 定义协议与偏好设置(加载数组长度)
先创建协议对象,添加偏好项指定存储数组长度的文件路径,同时实现偏好变更时的文件读取逻辑:
local my_proto = Proto("myproto", "My Custom Protocol") -- 偏好设置:指定存储数组长度的文件路径 local pref_array_len_file = Pref.string("array_length_file", "", "Path to file containing array length") -- 全局存储从文件读取的数组长度 local array_length = 0 -- 偏好变更时重新读取文件内容 function my_proto.prefs_changed() if pref_array_len_file.value ~= "" then local f = io.open(pref_array_len_file.value, "r") if f then array_length = tonumber(f:read("*a")) or 0 f:close() end end end
2. 定义通用字段(按需选择对应类型)
针对统一类型的数组,定义一个通用ProtoField,后续循环解析时复用,仅修改显示名称:
-- 示例:32位无符号整数类型数组 local generic_field = ProtoField.uint32("myproto.array.element", "Array Element", base.DEC) -- 如果是float类型数组,替换为: -- local generic_field = ProtoField.float("myproto.array.element", "Array Element") -- 如果是字符串类型数组(假设每个元素固定16字节),替换为: -- local generic_field = ProtoField.string("myproto.array.element", "Array Element") my_proto.fields = { generic_field }
3. 解析函数中处理变长数组
在 dissector 主函数里,定位数组起始偏移后,根据读取到的array_length循环解析每个元素:
function my_proto.dissector(buffer, pinfo, tree) pinfo.cols.protocol = my_proto.name local subtree = tree:add(my_proto, buffer(), "My Protocol Data") -- 假设数组从偏移4字节处开始,根据实际协议调整 local offset = 4 -- 仅当数组长度有效时执行解析 if array_length > 0 then local array_subtree = subtree:add(buffer(offset), string.format("Array (%d elements)", array_length)) for i = 0, array_length - 1 do local elem_name = string.format("Element [%d]", i) local elem_data = nil -- 根据数组类型读取对应长度的数据并解析 if generic_field.type == ftypes.UINT32 then elem_data = buffer(offset, 4) array_subtree:add(generic_field, elem_data):set_text(elem_name .. ": " .. elem_data:uint()) offset = offset + 4 elseif generic_field.type == ftypes.FLOAT then elem_data = buffer(offset, 4) array_subtree:add(generic_field, elem_data):set_text(elem_name .. ": " .. elem_data:float()) offset = offset + 4 elseif generic_field.type == ftypes.STRING then -- 字符串元素长度按需调整,这里假设为16字节 elem_data = buffer(offset, 16) array_subtree:add(generic_field, elem_data):set_text(elem_name .. ": " .. elem_data:string()) offset = offset + 16 end end end end -- 注册 dissector(示例:绑定到UDP端口1234,根据实际协议调整) local udp_port = DissectorTable.get("udp.port") udp_port:add(1234, my_proto)
关键细节说明
- 动态显示名称:通过
set_text()方法覆盖通用字段的默认名称,实现每个数组元素的个性化标识(如Element [0])。 - 类型适配:根据数组实际类型调整读取的字节长度和解析方法(
uint()/float()/string()),确保解析结果准确。 - 偏好生效逻辑:在
prefs_changed()回调中实时读取文件内容,修改偏好后无需重启Wireshark即可生效。
内容的提问来源于stack exchange,提问作者Arnault Bonafos
相关产品推荐
相关产品推荐

