--定义协议(第一个参数体现在过滤器中,第二个参数描述信息)
local hss_proto=Proto("Hss","Hss Protocol")
--定义字段(第一个参数为过滤条件,第二个参数为Tree列表中显示的名字,
--后面可以指定不同的进制显示方式:HEX为16进制,DEC为10进制)
--uint8,uint16,uint24,uint32分别表示1,2,3,4字节,即该字段的长度
local hss_proto_mark=ProtoField.uint16("hssMark","Mark",base.HEX,{[0x135d]="hss"})
local hss_proto_name=ProtoField.uint8("hssName","Name",base.HEX)
local hss_proto_version=ProtoField.uint8("hssVersion","Version",base.HEX)
local hss_proto_code=ProtoField.uint16("hssCode","Code",base.HEX,
{
[0x1B00]="JS_HSS_REGISTER_REQ",
[0x1B01]="JS_HSS_REGISTER_ACK",
[0X1B02]="JS_HSS_QUERY_REQ",
[0X1B03]="JS_HSS_QUERY_ACK",
[0X1B04]="JS_HSS_UNREGISTER_REQ",
[0X1B05]="JS_HSS_UNREGISTER _ACK"
}
)
local hss_proto_length=ProtoField.uint16("hssLength","Length",base.DEC)
local hss_proto_data=ProtoField.bytes("hssData","Data",base.NONE)
local data_tag=ProtoField.uint16("data_tag","Tag",base.HEX,
{
[0x1C00]="HANDLE",
[0x1C01]="MSISDN",
[0x1C02]="IMSI",
[0x1C03]="IMEI",
[0x1C04]="GWNAME",
[0x1C05]="DOMAIN",
[0x1C06]="EXPRIES",
[0x1C07]="RESULT",
[0x1C08]="ROUTER"
}
)
local data_length=ProtoField.uint16("data_length","Length",base.DEC)
local data_value_number=ProtoField.uint32("data_value_number","Value",base.DEC)
local data_value_string=ProtoField.string("data_value_string","Value")
--添加字段
hss_proto.fields={
hss_proto_mark,
hss_proto_name,
hss_proto_version,
hss_proto_code,
hss_proto_length,
hss_proto_data,
data_tag,
data_length,
data_value_number,
data_value_string
}
--buffer为数据流,pinfo为协议解析树上的信息,包括UI上的显示
function hss_proto.dissector(buffer,pinfo,tree)
offset = pinfo.desegment_offset or 0
--当前数据流长度
local buffer_len=buffer:len()
--该协议头部长度为8
local hssheadlength=8
local item=0
while true do
item=item+1
if offset==buffer_len then
return
end
--判断如果剩下的数据不到hssheadlength,即proto_length取不出来,就把pinfo.desegment_len返回
--DESEGMENT_ONE_MORE_SEGMENT表示不知道后面传进来的数据有多少
if offset+hssheadlength>buffer_len then
pinfo.desegment_offset=offset
pinfo.desegment_len=DESEGMENT_ONE_MORE_SEGMENT
return pinfo.desegment_len
end
local proto_length=buffer(offset+6,2):le_uint()
--剩下的数据能够取到hssheadlength的长度,判断剩下的数据能否够一条消息的长度,
--如果不够也返回pinfo.desegment_len
if offset+hssheadlength+proto_length>buffer_len then
pinfo.desegment_len=DESEGMENT_ONE_MORE_SEGMENT
pinfo.desegment_offset=offset
return pinfo.desegment_len
end
--ui层显示hss
pinfo.cols.protocol:set("hss")
--ui上添加信息,源端口和目标端口
pinfo.cols.info:set("hss protocol"..pinfo.src_port.."->"..pinfo.dst_port)
--解析树上添加协议,取前8个字节(head头部信息),显示为Hss Protocol。
local hssProtoTree=tree:add(hss_proto,buffer(offset,hssheadlength+proto_length),"Hss Protocol")
--解析树上添加信息,源端口和目标端口
hssProtoTree:append_text(",Src Port:"..pinfo.src_port..",Dst Port:"..pinfo.dst_port.."->".."item:"..item)
--添加字段到解析树上
hssProtoTree:add(hss_proto_mark,buffer(offset,2))
offset=offset+2
hssProtoTree:add(hss_proto_name,buffer(offset,1))
offset=offset+1
hssProtoTree:add(hss_proto_version,buffer(offset,1))
offset=offset+1
hssProtoTree:add(hss_proto_code,buffer(offset,2))
offset=offset+2
--le:uint()表示按小字节序将buffer(offset,2)的数据转换成无符号整数,uint()表示按照正常字节序转换
hssProtoTree:add(hss_proto_length,buffer(offset,2):le_uint())
offset=offset+2
doLength=offset-offset
--head解析完后,获取tlv格式的数据,并添加节点到树上
local hss_data=hssProtoTree:add(hss_proto_data,buffer(offset,proto_length))
--message()为调试函数,可以打印输出信息,可以在wireshark工具栏中,打开工具-lua-console,然后双击该协议,就会出现打印的信息
--message(buffer(offset,2))
--循环解析tlv格式的数据,doLength表示已解析的tlv数据长度
while proto_length>doLength do
--获取tag的值,为后面作判断使用
local data_tag_v=buffer(offset,2):uint()
hss_data:add(data_tag,buffer(offset,2))
offset=offset+2
doLength=doLength+2
local value_length=buffer(offset,2):le_uint()
hss_data:add(data_length,buffer(offset,2):le_uint())
offset=offset+2
doLength=doLength+2
--判断tag的类型,number类型和string类型分别处理,number为4字节固定,string不固定
if data_tag_v==0x1c00 or
data_tag_v==0x1c05 or
data_tag_v==0x1c06 or
data_tag_v==0x1c07 or
data_tag_v==0x1c08
then
hss_data:add(data_value_number,buffer(offset,value_length):le_uint())
else
hss_data:add(data_value_string,buffer(offset,value_length))
end
offset=offset+value_length
doLength=doLength+value_length
end
end
end
--向wireshark注册协议插件被调用的条件
local tcp_port_table=DissectorTable.get("tcp.port")
tcp_port_table:add(14983,hss_proto)
(1).定义新的协议(Proto主要用途是声明一个新的协议,括号中第一个参数体现在过滤 器中,第二个参数描述信息)
举例:
local hss_proto=Proto("Hss","Hss Protocol")
(2).定义字段
(第一个参数为过滤条件,第二个参数为Tree列表中显示的名字,
后面可以指定不同的进制显示方式:HEX为16进制,DEC为10进制
uint8,uint16,uint24,uint32,分别表示1,2,3,4字节,即该字段的长度
bytes表示该字段的字节有哪些,string表示该字段用字符串表示,
后面还可以显示指定特定字节所表示的含义)
举例:
Local hss_proto_mark=ProtoField.uint16("hssMark","Mark",base.HEX,
{[0x5d13]="hss",[0x135d]="hss"})
local hss_proto_name=ProtoField.uint8("hssName","Name",base.HEX)
local hss_proto_data=ProtoField.bytes("hssData","Data",base.NONE)
local data_value_string=ProtoField.string("data_value_string","Value")
(3).将字段添加到定义好的协议中,不然无法添加到解析树上
hss_proto.fields={
hss_proto_mark,
hss_proto_name,
hss_proto_version,
hss_proto_code,
hss_proto_length,
hss_proto_data,
data_tag,
data_length,
data_value_number,
data_value_string
}
(4).创建解析器
function hss_proto.dissector(buffer,pinfo.tree)
在方法里面写具体的解析过程
(参数含义:buffer为数据流,pinfo为协议解析树上的信息和UI层上的显示,tree 为协议解析树,将我们定义好的字段添加到树上)
end
具体解析过程:
Hss模块(mark,name,version,code,length,value),由于数据发送过来的长度不确定,解析需循环处理
1.获取buffer数据流长度:local buffer_len=buffer:len()
定义一个变量offset,表示指针位置
2.往解析树上添加协议,取前8个字节(head头部信息),显示为Hss Protocol
local hssProtoTree=tree:add(hss_proto,buffer(offset,8+proto_length),"Hss Protocol")
3.添加字段到解析树上
hssProtoTree:add(hss_proto_mark,buffer(offset,2))
offset=offset+2
hssProtoTree:add(hss_proto_name,buffer(offset,1))
offset=offset+1
hssProtoTree:add(hss_proto_version,buffer(offset,1))
offset=offset+1
hssProtoTree:add(hss_proto_code,buffer(offset,2))
offset=offset+2
hssProtoTree:add(hss_proto_length,buffer(offset,2):le_uint())
offset=offset+2
le:uint()表示按小字节序将buffer(offset,2)的数据转换成无符号整数
4.head头部解析完后,获取tlv格式的value数据,并添加到节点树上
local hss_data=hssProtoTree:add(hss_proto_data,buffer(offset,proto_length))
doLength=0
5.循环解析tlv格式的数据,doLength表示已解析的当条消息的tlv数据长度
while proto_length>doLength do
local data_tag_v=buffer(offset,2):le_uint()
hss_data:add(data_tag,buffer(offset,2))
offset=offset+2
doLength=doLength+2
local value_length=buffer(offset,2):le_uint()
hss_data:add(data_length,buffer(offset,2):le_uint())
offset=offset+2
doLength=doLength+2
--判断tag的类型,number类型和string类型分别处理,number为4字节固定,string不固定
if data_tag_v==28 or
data_tag_v==1308 or
data_tag_v==1564 or
data_tag_v==1820 or
data_tag_v==2076
then
hss_data:add(data_value_number,buffer(offset,value_length):le_uint())
else
hss_data:add(data_value_string,buffer(offset,value_length))
end
offset=offset+value_length
doLength=doLength+value_length
end
3.向wireshark注册协议插件被调用的条件
local tcp_port_table=DissectorTable.get("tcp.port")
tcp_port_table:add(14983,hss_proto)
4.至此,整条的协议能循环解析出来,后面处理0.5条之类的数据
pinfo有两个属性pinfo.desegment_len,和pinfo.desegment_offset,分别表示后面的数据长度和已解析的标志位,当遇到含有1.3条之类的数据的时候,取出后面的0.3条,放入下一条的头部,在解析器中体现在返回值上(DESEGMENT_ONE_MORE_SEGMENtT表示不知道后面数据的长度),用一个判断语句去表示
if offset+8+proto_length>buffer_len then
pinfo.desegment_len=DESEGMENT_ONE_MORE_SEGMENT pinfo.desegment_offset=offset
return pinfo.desegment_len
end
5.lua解析器会自动把前一条未解析的数据和当条数据合并后再解析
(2)
(3)
解析出来的hss协议如图所示: