https://github.com/leizhiyuan/bolt-dissector
自己平常看协议,经常看到眼花,所以写了一个解析 SOFARPC 中 BOLT 协议的 wiresharks 插件
Wireshark是排查网络问题最常用的工具,它已经内置支持了上百种通用协议,扩展性也好,对于私有协议,还是得自己写的.对 C 不熟,但是 Lua 看了一下语法,还是挺简单的.
插件是使用lua开发的,安装比较简单,以OS X平台为例:
- 将协议解析脚本拷贝到/Applications/Wireshark.app/Contents/Resources/share/wireshark/ 目录
- (非必须) 编辑init.lua文件,设置disable_lua = false,确保lua支持打开,默认是打开的.一般就不要操作了.
- 在init.lua文件末尾增加,当然你也可以写全路径.
``
dofile("bolt.lua")
- 再次启动Wireshark,会对12200端口的数据流使用脚本解析,已经可以识别BOLT协议了。
参考文档
https://wiki.wireshark.org/LuaAPI
附上 lua脚本 目前只支持 boltv1,稍后看看改一下支持 boltv2和 tr,方便大家理解 和抓包.
---
--- Created by bystander.
--- DateTime: 2018/11/16 8:57 AM
---
-- declare the protocol
bolt_proto = Proto("bolt", "SOFA BOLT Protocol")
-- declare the value strings
local vs_proto = {
[1] = "BOLT",
[13] = "TR",
}
local vs_type = {
[1] = "Request",
[2] = "Request Oneway",
[0] = "Response",
}
local vs_cmdcode = {
[0] = "HeartBeat",
[1] = "Request",
[2] = "Response",
}
local vs_version2 = {
[1] = "v1",
[2] = "v2",
}
local vs_codec = {
[1] = "HESSIAN_CODEC",
[2] = "JAVA_CODEC",
[11] = "PROTOBUF_CODEC",
}
local vs_responsestatus = {
[00] = "Success",
[01] = "Error",
[02] = "Server Exception",
[03] = "Unknown Exception",
[04] = "Server Thread Pool Busy",
[05] = "Error Communication",
[06] = "No Processor",
[07] = "Timeout Exception",
[08] = "Client Send Error",
[09] = "Codec Exception",
[10] = "Connection Closed",
[11] = "Server Serialize Exception",
[12] = "Server DeSerialize Exception",
}
-- declare the fields
local f_proto = ProtoField.uint8("bolt.proto", "Protocode", base.Dec, vs_proto)
local f_type = ProtoField.uint8("bolt.type", "Type", base.Dec, vs_type)
local f_cmdcode = ProtoField.uint16("bolt.cmdcode", "Cmdcode", base.Dec, vs_cmdcode)
local f_version2 = ProtoField.uint8("bolt.version", "Version", base.Dec, vs_version2)
local f_req_id = ProtoField.uint32("bolt.reqid", "RequestID", base.DEC)
local f_codec = ProtoField.uint8("bolt.codec", "Codec", base.DEC, vs_codec)
local f_timeout = ProtoField.uint32("bolt.timeout", "Timeout", base.DEC)
local f_response_status = ProtoField.uint32("bolt.response.status", "Response Status", base.DEC, vs_responsestatus)
local f_classlen = ProtoField.uint16("bolt.classlen", "Classlen", base.DEC)
local f_headerlen = ProtoField.uint16("bolt.headerlen", "Headerlen", base.DEC)
local f_contentlen = ProtoField.uint32("bolt.contentlen", "Contentlen", base.DEC)
local f_class = ProtoField.string("bolt.class", "Class")
local f_header = ProtoField.bytes("bolt.header", "Header")
local f_content = ProtoField.bytes("bolt.content", "Content")
bolt_proto.fields = { f_proto, f_type, f_cmdcode, f_version2, f_req_id, f_codec, f_timeout, f_response_status,
f_classlen, f_headerlen, f_contentlen, f_class, f_header, f_content
}
function get_pdu_length(buffer)
local offset = 0
local proto = buffer(offset, 1):uint()
offset = offset + 1
-- BOLT
if proto == 1 then
local dataType = buffer(offset, 1):uint()
if dataType == 1 or dataType == 2 then
if buffer:len() < 22 then
return 22
end
-- 继续
local classLen = buffer(14, 2):uint64()
local headerLen = buffer(16, 2):uint64()
local contentLen = buffer(18, 4):uint64()
return 22 + classLen + headerLen + contentLen
end
--response
if dataType == 0 then
if buffer:len() < 20 then
return 20
end
-- 继续
local classLen = buffer(12, 2):uint64()
local headerLen = buffer(14, 2):uint64()
local contentLen = buffer(16, 4):uint64()
return 20 + classLen + headerLen + contentLen
end
end
end
-- create the dissection function
function bolt_proto.dissector(buffer, pinfo, tree)
-- check the protocol
local check_proto = buffer(0, 1):uint()
if check_proto ~= 1 then
return
end
-- Set the protocol column
pinfo.cols['protocol'] = "BOLT"
-- Reassembling packets into one PDU
local pdu_len = get_pdu_length(buffer)
if pdu_len > buffer:len() then
pinfo.desegment_len = pdu_len - buffer:len()
pinfo.desegment_offset = 0
return
end
-- create the BOLT protocol tree item
local t_bolt = tree:add(bolt_proto, buffer())
local offset = 0
local protocol = buffer(offset, 1):uint()
offset = offset + 1
t_bolt:add(f_proto, protocol)
-- TB REMOTING
if protocol == 13 then
-- NOT easy
end
-- BOLT REMOTING
if protocol == 1 then
local dataType = buffer(offset, 1):uint()
t_bolt:add(f_type, dataType)
offset = offset + 1
-- Set the info column to the name of the function
local info = vs_proto[protocol] .. ":" .. vs_type[dataType]
pinfo.cols['info'] = info
-- request
if dataType == 1 or dataType == 2 then
t_bolt:add(f_cmdcode, buffer(offset, 2))
offset = offset + 2
t_bolt:add(f_version2, buffer(offset, 1))
offset = offset + 1
t_bolt:add(f_req_id, buffer(offset, 4))
offset = offset + 4
t_bolt:add(f_codec, buffer(offset, 1))
offset = offset + 1
t_bolt:add(f_timeout, buffer(offset, 4))
offset = offset + 4
t_bolt:add(f_classlen, buffer(offset, 2))
local classLen = buffer(offset, 2):uint64():tonumber()
offset = offset + 2
t_bolt:add(f_headerlen, buffer(offset, 2))
local headerLen = buffer(offset, 2):uint64():tonumber()
offset = offset + 2
t_bolt:add(f_contentlen, buffer(offset, 4))
local contentLen = buffer(offset, 4):uint64():tonumber()
offset = offset + 4
t_bolt:add(f_class, buffer(offset, classLen))
offset = offset + classLen
t_bolt:add(f_header, buffer(offset, headerLen))
offset = offset + headerLen
t_bolt:add(f_content, buffer(offset, contentLen))
offset = offset + contentLen
end
-- response
if dataType == 0 then
t_bolt:add(f_cmdcode, buffer(offset, 2))
offset = offset + 2
t_bolt:add(f_version2, buffer(offset, 1))
offset = offset + 1
t_bolt:add(f_req_id, buffer(offset, 4))
offset = offset + 4
t_bolt:add(f_codec, buffer(offset, 1))
offset = offset + 1
t_bolt:add(f_response_status, buffer(offset, 2))
offset = offset + 2
t_bolt:add(f_classlen, buffer(offset, 2))
local classLen = buffer(offset, 2):uint64():tonumber()
offset = offset + 2
t_bolt:add(f_headerlen, buffer(offset, 2))
local headerLen = buffer(offset, 2):uint64():tonumber()
offset = offset + 2
t_bolt:add(f_contentlen, buffer(offset, 4))
local contentLen = buffer(offset, 4):uint64():tonumber()
offset = offset + 4
t_bolt:add(f_class, buffer(offset, classLen))
offset = offset + classLen
t_bolt:add(f_header, buffer(offset, headerLen))
offset = offset + headerLen
t_bolt:add(f_content, buffer(offset, contentLen))
offset = offset + contentLen
end
end
end
-- we use 12200
tcp_table = DissectorTable.get("tcp.port")
-- register the protocol to port 12200
tcp_table:add(12200, bolt_proto)