在C++中编写Wireshark解析器插件:packed BCD编码解析疑问
嘿,你这个问题我之前做类似插件时也碰到过——Wireshark确实没内置Packed BCD的直接支持,但你的临时方案虽然能显示,最大的问题是没法利用Wireshark的过滤、统计这些核心功能,毕竟proto_item_set_text只是改了显示文本,底层字段值还是原始字节,用户没法用protocol.foo == 123456789012这类规则过滤。
给你两个更优的方案,完全适配Wireshark的工作流:
方案1:转换为数值类型(推荐,支持数值过滤)
如果你的Packed BCD是用来存储十进制整数(比如12位ID、金额),直接把它转换成uint64_t(12位十进制最大是999999999999,远小于uint64_t的上限),然后用标准的数值字段添加方法:
步骤1:定义字段为数值类型
在field_array里把字段注册成FT_UINT64(如果是有符号数就用FT_INT64):
static hf_register_info field_array[] = { { &fields.foo, { "Foo Field", "protocol.foo", FT_UINT64, BASE_DEC, NULL, 0x0, "12-digit Packed BCD value", HFILL } }, // 其他字段... };
步骤2:编写Packed BCD转数值的工具函数
uint64_t packed_bcd_to_uint64(tvbuff_t *tvb, gint offset, gint length) { uint64_t result = 0; for (gint i = 0; i < length; i++) { guint8 byte = tvb_get_guint8(tvb, offset + i); // 每个字节的高4位是十位,低4位是个位 result = result * 100 + ((byte >> 4) & 0x0F) * 10 + (byte & 0x0F); } return result; }
步骤3:在解析器中使用
替换原来的proto_tree_add_item,改用数值添加方法:
uint64_t foo_value = packed_bcd_to_uint64(tvb, offset, 6); // 6字节对应12位十进制 proto_tree_add_uint64(body, fields.foo, tvb, offset, 6, foo_value);
这样一来,Wireshark不仅会显示转换后的十进制数值,还支持数值过滤、排序、统计,完全和原生字段一样。
方案2:转换为字符串类型(适合带格式的场景)
如果你的Packed BCD需要显示为带前导零的字符串(比如固定12位的编号),可以转换成ASCII字符串,注册为FT_STRING类型:
步骤1:定义字段为字符串类型
static hf_register_info field_array[] = { { &fields.foo, { "Foo Field", "protocol.foo", FT_STRING, BASE_NONE, NULL, 0x0, "12-digit Packed BCD string", HFILL } }, // 其他字段... };
步骤2:编写Packed BCD转字符串的工具函数
gchar* packed_bcd_to_string(tvbuff_t *tvb, gint offset, gint length) { gchar* str = (gchar*)g_malloc0(length * 2 + 1); // 每个字节对应2个字符 for (gint i = 0; i < length; i++) { guint8 byte = tvb_get_guint8(tvb, offset + i); str[i*2] = '0' + ((byte >> 4) & 0x0F); str[i*2+1] = '0' + (byte & 0x0F); } return str; }
步骤3:在解析器中使用
gchar* foo_str = packed_bcd_to_string(tvb, offset, 6); proto_tree_add_string(body, fields.foo, tvb, offset, 6, foo_str); g_free(foo_str); // 记得释放内存!
这个方案适合需要精确字符串匹配过滤的场景,比如protocol.foo contains "1234"。
额外优化:同时显示原始字节和转换后的值
如果想让用户同时看到转换后的值和原始Packed BCD字节,可以用proto_item_append_text补充显示:
proto_item* foo_item = proto_tree_add_uint64(body, fields.foo, tvb, offset, 6, foo_value); proto_item_append_text(foo_item, " (raw: %s)", tvb_bytes_to_str_punct(tvb, offset, 6, ':'));
这样详情面板里会显示类似123456789012 (raw: 12:34:56:78:90:12)的内容,方便调试。
内容的提问来源于stack exchange,提问作者Anton

