工欲善其事,必先利其器-redis 6.0 RCMB集群协议wireshark解析插件
先看效果
代码实现
需要修改适配相关的端口,或者wireshark设置强制解析
do
-- 简单的认为单个tcp报文就是单个rcmb消息,假设不会拆包或者合包
local p_RCMB = Proto("RCMB","Redis Cluster message bus")
--RCmb协议的基础字段
local base_sig = ProtoField.string("RCMB.sig","Sig")
local base_totlen = ProtoField.uint32("RCMB.totlen","TotLen",base.DEC)
local base_ver = ProtoField.uint16("RCMB.ver","Ver",base.DEC)
local base_port = ProtoField.uint16("RCMB.port","Port",base.DEC)
local base_type = ProtoField.uint16("RCMB.type","Type",base.DEC,
{ [0] = "PING", [1] = "PONG", [2] = "MEET", [3] = "FAIL", [4] = "PUBLISH",
[5] = "FAILOVER_AUTH_REQUEST", [6] = "FAILOVER_AUTH_ACK",
[7] = "UPDATE", [8] = "MFSTART", [9] = "MODULE"})
local base_count = ProtoField.uint16("RCMB.count","Count",base.DEC)
local base_currentEpoch = ProtoField.uint64("RCMB.currentEpoch","CurrentEpoch",base.DEC)
local base_configEpoch = ProtoField.uint64("RCMB.configEpoch","ConfigEpoch",base.DEC)
local base_offset = ProtoField.uint64("RCMB.offset","Offset",base.DEC)
local base_sender = ProtoField.string("RCMB.sender","Sender")
local base_myslots = ProtoField.bytes("RCMB.myslots","Myslots")
local base_slaveof = ProtoField.string("RCMB.slaveof","Slaveof")
local base_myip = ProtoField.string("RCMB.myip","Myip")
local base_notused1 = ProtoField.bytes("RCMB.notused1","Notused1")
local base_cport = ProtoField.uint16("RCMB.cport","Cport",base.DEC)
local base_flags = ProtoField.uint16("RCMB.flags","Flags",base.DEC)
local base_state = ProtoField.uint8("RCMB.state","State",base.DEC,
{ [0] = "CLUSTER_OK", [1] = "CLUSTER_FAIL"})
local base_mflags = ProtoField.bytes("RCMB.mflags","Mflags")
-- ping消息字段
local gossip_nodename = ProtoField.string("RCMB.gossip_nodename","Gossip_nodename")
local gossip_ping_sent = ProtoField.uint32("RCMB.gossip_ping_sent","Gossip_ping_sent",base.DEC)
local gossip_pong_received= ProtoField.uint32("RCMB.gossip_pong_received","Gossip_pong_received",base.DEC)
local gossip_ip = ProtoField.string("RCMB.gossip_ip","Gossip_ip")
local gossip_port = ProtoField.uint16("RCMB.gossip_port","Gossip_port",base.DEC)
local gossip_cport = ProtoField.uint16("RCMB.gossip_cport","Gossip_cport",base.DEC)
local gossip_flags = ProtoField.uint16("RCMB.gossip_flags","Gossip_flags",base.DEC)
local gossip_notused1= ProtoField.uint32("RCMB.gossip_notused1","Gossip_notused1",base.DEC)
-- fail消息字段
local fail_nodename = ProtoField.string("RCMB.fail_nodename","Fail_nodename")
-- publish消息字段
local publish_channel_len= ProtoField.uint32("RCMB.publish_channel_len","Publish_channel_len",base.DEC)
local publish_message_len= ProtoField.uint32("RCMB.publish_message_len","Publish_message_len",base.DEC)
local publish_bulk_data = ProtoField.bytes("RCMB.publish_bulk_data","Publish_bulk_data")
-- update消息字段
local update_configEpoch= ProtoField.uint64("RCMB.update_configEpoch","Update_configEpoch",base.DEC)
local update_nodename = ProtoField.string("RCMB.update_nodename","Update_nodename")
local update_slots = ProtoField.bytes("RCMB.update_slots","Update_slots")
-- module消息字段
local module_id = ProtoField.uint64("RCMB.module_id","Module_id",base.DEC)
local module_len = ProtoField.uint32("RCMB.module_len","Module_len",base.DEC)
local module_type = ProtoField.uint8("RCMB.module_type","Module_type",base.DEC)
local module_bulk_data = ProtoField.bytes("RCMB.module_bulk_data","Module_bulk_data")
p_RCMB.fields = { base_sig, base_totlen, base_ver, base_port, base_type, base_count, base_currentEpoch, base_configEpoch, base_offset,
base_sender, base_myslots, base_slaveof, base_myip, base_notused1, base_cport, base_flags, base_state, base_mflags,
gossip_nodename, gossip_ping_sent, gossip_pong_received, gossip_ip, gossip_port, gossip_cport, gossip_flags, gossip_notused1,
fail_nodename,
publish_channel_len, publish_message_len, publish_bulk_data,
update_configEpoch, update_nodename, update_slots,
module_id,module_len,module_type,module_bulk_data}
local data_dis = Dissector.get("data")
local function RCMB_dissector(buf,pkt,root)
local buf_len = buf:len();
-- 先确保至少有4个byte存放"RCmb"
if buf_len < 4 then return false end
if (buf(0,4):uint()~=1380150626)
-- 1380150626为RCmc的uint32表示
then return false end
local t = root:add(p_RCMB,buf)
pkt.cols.protocol = "RCMB"
t:add(base_sig,buf(0,4))
t:add(base_totlen,buf(4,4))
t:add(base_ver,buf(8,2))
t:add(base_port,buf(10,2))
-- 记录type信息,用于后续根据type解析不同字段
local i_type = buf(12,2):uint()
t:add(base_type,buf(12,2))
t:add(base_count,buf(14,2))
t:add(base_currentEpoch,buf(16,8))
t:add(base_configEpoch,buf(24,8))
t:add(base_offset,buf(32,8))
t:add(base_sender,buf(40,40))
t:add(base_myslots,buf(80,2048))
t:add(base_slaveof,buf(2128,40))
t:add(base_myip,buf(2168,46))
t:add(base_notused1,buf(2214,34))
t:add(base_cport,buf(2248,2))
t:add(base_flags,buf(2250,2))
t:add(base_state,buf(2252,1))
t:add(base_mflags,buf(2253,3))
-- 按照消息类型分类型解析
if (i_type == 0) then
--把存在的字段逐个添加进去
t:add(gossip_nodename,buf(2256,40))
t:add(gossip_ping_sent,buf(2296,4))
t:add(gossip_pong_received,buf(2300,4))
t:add(gossip_ip,buf(2304,46))
t:add(gossip_port,buf(2350,2))
t:add(gossip_cport,buf(2352,2))
t:add(gossip_flags,buf(2354,2))
t:add(gossip_notused1,buf(2256,4))
elseif (i_type == 3) then
t:add(fail_nodename,buf(2256,40))
elseif (i_type == 4) then
t:add(publish_channel_len, buf(2256,4))
t:add(publish_message_len, buf(2260,4))
t:add(publish_bulk_data, buf(2264,8))
elseif (i_type == 7) then
t:add(update_configEpoch,buf(2256,8))
t:add(update_nodename,buf(2264,40))
t:add(update_slots,buf(2304,2048))
elseif (i_type == 9) then
t:add(module_id,buf(2256,8))
t:add(module_len,buf(2264,4))
t:add(module_type,buf(2268,2))
t:add(module_bulk_data,buf(2270,3))
end
return true
end
function p_RCMB.dissector(buf,pkt,root)
if RCMB_dissector(buf,pkt,root) then
--valid RCMB diagram
else
--data这个dissector几乎是必不可少的;当发现不是我的协议时,就应该调用data
-- return 0;同样效果?
data_dis:call(buf,pkt,root)
end
end
local tcp_port_table = DissectorTable.get("tcp.port")
--只需要处理UDP1127端口就可以了
tcp_port_table:add(40001,p_RCMB)
for i,port in ipairs{40002,40003, 40004, 40005, 40006} do
tcp_port_table:add(port,p_RCMB)
end
end
补充:
- 实现参考: https://www.jianshu.com/p/1e2f63a484d6
- TCP解析复杂处理https://wiki.wireshark.org/Lua/Examples?action=AttachFile&do=get&target=fpm.lua
附件列表