Wireshark(前称Ethereal)是一个网络封包分析软件。网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料。自己在工作过程过程中涉及到大量udp自定义报文的录取,于是想着采用Wireshark来完成这一工作。通过调研发现Wireshark解析自定义报文的方式有C语言和lua语言两种方式,前者需要编译代码,但效率高,后者可以动态加载效率逊于C的方式,但使用方便,结合自己的使用需求,采用Lua语言的方式。
自定义报文结构
报文由报文头和报文体构成,报文标识之前的字段算作报文头,报文头格式不不会发生变化,报文标识后面的内容为报文体,报文标识不同,报文体的格式也不同。
设备电压状态
字段 | 字节 | 值 | 备注 |
---|---|---|---|
识别码 | 1 | 0x55aa | |
目的ip地址 | 4 | ||
报文标识 | 4 | 0x33300001 | 用于识别该报文类型 |
设备个数 | 1 | 用于表示设备个数 | |
设备1编号 | 4 | 0x80000001:1号设备,0x80000002:2号设备 | |
设备1电压 | 4 | 单位:V | |
... | ... | ... | ... |
设备N编号 | 4 | ||
设备N电压 | 4 |
设备故障状态
字段 | 字节 | 值 | 备注 |
---|---|---|---|
识别码 | 1 | 0x55aa | |
目的ip地址 | 4 | ||
报文标识 | 4 | 0x33300002 | 用于识别该报文类型 |
设备个数 | 1 | 用于表示设备个数 | |
设备1编号 | 4 | 0x80000001:1号设备,0x80000002:2号设备 | |
设备1故障状态 | 1 | 0x00:未知,0x01:正常,0x02:故障 | |
... | ... | ... | ... |
设备N编号 | 4 | ||
设备N故障状态 | 1 |
Lua脚本
报文头解析脚本
-----------------------------------------------------------------
-- myheader.lua
-----------------------------------------------------------------
--解析器map,用于根据标识获取对应的协议解析器
protos={
--电压报文
[0x33300001]=Dissector.get("my_voltage_proto"),
--设备状态报文
[0x33300002]=Dissector.get("my_state_proto")
}
--基于UDP协议
local udp_table = DissectorTable.get("udp.port")
local hb_proto = Proto("my-proto", "my-proto", "my-proto")
--协议端口号
local hb_port = 0x5800
--定义协议字段内容
local identifycode = ProtoField.uint8("idenfifycode", "识别码", base.HEX)
local dest_ip = ProtoField.ipv4("dest-ip", "目的ip")
local flag=ProtoField.uint32("flag","报文标志",base.HEX,flagdesc)
hb_proto.fields = {identifycode,dest_ip,flag}
--协议分析器
function hb_proto.dissector(buffer, pinfo, tree)
--开始解析报文头
pinfo.cols.protocol:set("自定义报文")
local len = buffer:len()
local myProtoTree = tree:add(hb_proto, buffer(0, len), "自定义报文头")
local offset = 0
myProtoTree:add(identifycode, buffer(offset, 1))
offset=offset+1
myProtoTree:add(dest_ip, buffer(offset, 4))
offset=offset+4
myProtoTree:add(flag, buffer(offset, 4))
offset=offset+4
--获取该报文的标识
local temp_flag=buffer(5,4):uint()
if(protos[temp_flag]~=nil)
then
--根据标识获取解析器,并解析报文体
protos[temp_flag]:call(buffer(offset):tvb(),pinfo,tree)
else
pinfo.cols.protocol:set("未知报文")
end
end
--增加协议到Wireshark中
udp_table:add(hb_port, hb_proto)
设备电压报文解析脚本
-----------------------------------------------------------------
-- myvoltage.lua
-----------------------------------------------------------------
--电压报文
local voltage_proto = Proto("my_voltage_proto", "电压报文")
local deviceid=ProtoField.uint16("deviceid","设备id",base.HEX,{[0x8001] = "1号设备",[0x8002] = "2号设备"})
local voltage=ProtoField.uint16("voltage","电压",base.Dec)
voltage_proto.fields = {deviceid, voltage}
--协议分析器
function voltage_proto.dissector(buffer, pinfo, tree)
pinfo.cols.protocol:set(voltage_proto.description)
local len = buffer:len()
local myProtoTree = tree:add(voltage_proto, buffer(0, len), voltage_proto.description)
local offset = 0
local cnt=len/4
for i=1,cnt do
myProtoTree:add(deviceid, buffer(offset, 2))
offset=offset+2
myProtoTree:add(voltage, buffer(offset,2))
offset=offset+2
end
end
设备状态报文解析脚本
-----------------------------------------------------------------
-- mystate.lua
-----------------------------------------------------------------
--状态报文
local state_proto = Proto("my_state_proto", "设备状态")
local deviceid=ProtoField.uint16("deviceid","设备id",base.HEX,{[0x8001] = "1号设备",[0x8002] = "2号设备"})
local state=ProtoField.uint16("state","设备状态",base.HEX,{[0x00] = "正常",[0x01] = "故障",[0x02] = "未知"})
state_proto.fields = {deviceid, state}
--协议分析器
function state_proto.dissector(buffer, pinfo, tree)
pinfo.cols.protocol:set(state_proto.description)
local len = buffer:len()
local myProtoTree = tree:add(state_proto, buffer(0, len), state_proto.description)
local offset = 0
local cnt=len/4
for i=1,cnt do
myProtoTree:add(deviceid, buffer(offset, 2))
offset=offset+2
myProtoTree:add(state, buffer(offset,2))
offset=offset+2
end
end
添加脚本文件
在将以上三个Lua文件放在wireshark根目录下,并修改该目录下的init.lua文件,在文件末尾添加这三个文件,
dofile(DATA_DIR.."mystate.lua")
dofile(DATA_DIR.."myvoltage.lua")
dofile(DATA_DIR.."myheader.lua")
重启wireshark即可,如果脚本有错误,wireshark会给与提示
过滤功能
可以使用wireshark强大的过滤功能来分析已经录取的报文,它支持对自定义的字段进行过滤查询,例如想查看报文标识为0x33300001的报文
其他
通过wireshark配合tcpdump+tcpreplay等工具可以方便的实现linux环境下基于自定义报文的分析,录取和回放等功能。