前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为Wireshark编写HSF2协议解析插件

为Wireshark编写HSF2协议解析插件

作者头像
mazhen
发布2023-11-24 13:59:00
1160
发布2023-11-24 13:59:00
举报
文章被收录于专栏:mazhen.techmazhen.tech

Wireshark是排查网络问题最常用的工具,它已经内置支持了上百种通用协议,同时它的扩展性也很好,对于自定义的应用层网络协议,你可以使用c或者lua编写协议解析插件,这样你就可以在Wireshark中观察到协议的内容而不是二进制流,为排查问题带来一定的便利性。

最近在排查一个HSF超时的问题,顺便花了些时间为Wireshark写了一个HSF2协议解析插件,目前支持HSF2requestresponseheart beat协议,支持将多个packet还原为上层PDU。暂不支持HSF原先的TB Remoting协议。先看效果。

首先在Packet List区域已经能识别HSF2协议:

HSF的请求和响应

HSF的心跳协议

点击某个数据包,可以在Packet details区域查看详细的协议内容: HSF请求

可以看到很多协议的重要信息,包括序列化方式,超时时间,服务名称、方法及参数

HSF响应

HeartBeat请求

心跳协议比较简单,响应就不看了。

插件是使用lua开发的,安装比较简单,以OS X平台为例:

将协议解析脚本copy到/Applications/Wireshark.app/Contents/Resources/share/wireshark/ 目录

编辑init.lua文件,设置disable_lua = false,确保lua支持打开

init.lua文件末尾增加

代码语言:javascript
复制
dofile("hsf2.lua")

再次启动Wireshark,会对12200端口的数据流使用脚本解析,已经可以识别HSF协议了。

备注

附上hsf2.lua,边翻HSF代码边写的,写完眼已经花了,错误难免,欢迎试用。

代码语言:javascript
复制
-- declare the protocol
hsf2_proto = Proto("hsf2", "Taobao HSF2 Protocol")

-- declare the value strings
local vs_id = {
    [12] = "HSF2 Heart Beat",
    [13] = "HSF2 TB Remoting",
    [14] = "HSF2 HSF Remoting"  
}

local vs_version = {
    [1] = "HSF2"
}

local vs_op = {
    [0] = "request",
    [1] = "response"
}

local vs_codectype = {
    [1] = "HESSIAN_CODEC",
    [2] = "JAVA_CODEC",
    [3] = "TOP_CODEC",
    [4] = "HESSIAN2_CODEC",
    [5] = "KRYO_CODEC",
    [6] = "JSON_CODEC",
    [7] = "CUSTOMIZED_CODEC",
}

local vs_responsestatus = {
    [20] = "OK",
    [30] = "client timeout",
    [31] = "server timeout",
    [40] = "bad request",
    [50] = "bad response",
    [60] = "service not found",
    [70] = "service error",
    [80] = "server error",
    [90] = "client error",
    [91] = "Unknow error",
    [81] = "Thread pool is busy",
    [82] = "Communication error",
    [88] = "server will close soon",
    [10] = "server send coders",
    [83] = "Unkown code"
}

-- declare the fields
local f_id = ProtoField.uint8("hsf2.id", "Identification", base.Dec, vs_id)
local f_version = ProtoField.uint8("hsf2.version", "version", base.Dec, vs_version)
local f_op = ProtoField.uint8("hsf2.op", "operation", base.DEC, vs_op)
local f_codectype = ProtoField.uint8("hsf2.codectype", "codectype", base.DEC, vs_codectype)
local f_reserved = ProtoField.uint8("hsf2.reserved", "reserved", base.DEC)
local f_req_id = ProtoField.uint64("hsf2.req_id", "RequestID", base.DEC)
local f_timeout = ProtoField.uint32("hsf2.timeout", "timeout", base.DEC)
local f_service_name_len = ProtoField.uint32("hsf2.service_name_len", "Service Name length", base.DEC)
local f_method_name_len = ProtoField.uint32("hsf2.method_name_len", "Method Name length", base.DEC)
local f_arg_count = ProtoField.uint32("hsf2.arg.count", "Argument Count", base.DEC)
local f_arg_type_len = ProtoField.uint32("hsf2.arg.type.len", "Argument Type length", base.DEC)
local f_arg_obj_len = ProtoField.uint32("hsf2.arg.obj.len", "Argument Object length", base.DEC)
local f_req_prop_len = ProtoField.uint32("hsf2.req.prop.len", "Request Prop Length", base.DEC)
local f_service_name = ProtoField.string("hsf2.service.name", "Service Name")
local f_method_name = ProtoField.string("hsf2.method.name", "Method Name")
local f_arg_type = ProtoField.string("hsf2.arg.type", "Argument Type")
local f_arg_obj = ProtoField.bytes("hsf2.arg.obj", "Argument Object")
local f_req_prop = ProtoField.bytes("hsf2.req.prop", "Request Prop")

local f_response_status = ProtoField.uint32("hsf2.response.status", "Response Status", base.DEC, vs_responsestatus)
local f_response_body_len = ProtoField.uint32("hsf2.response.body.len", "Response Body Length", base.DEC)
local f_response_body = ProtoField.bytes("hsf2.response.body", "Response Body", base.DEC)


hsf2_proto.fields = { f_id, f_version, f_op, f_codectype, f_reserved, f_req_id, f_timeout, 
                      f_service_name_len, f_method_name_len, f_arg_count, f_arg_type_len, f_arg_obj_len, f_req_prop_len,
                      f_service_name, f_method_name, f_arg_type, f_arg_obj, f_req_prop, 
                      f_response_status, f_response_body_len, f_response_body
                    }


function get_pdu_length(buffer)
    local offset =  0
    local id = buffer(offset, 1):uint()
    offset = offset + 1
    -- heart beat
    if id  == 12 then
        return 18 
    end
    -- TB REMOTING
    if id == 13 then
      -- TODO
        return 18
    end
    -- HSF REMOTING
    if id == 14 then
        local version = buffer(offset, 1):uint()
        offset = offset + 1
        local op = buffer(offset, 1):uint()
        offset = offset + 1
        -- request
        if op == 0 then
          local service_name_len = buffer(19, 4):uint()
          local method_name_len = buffer(23,4):uint()
          local arg_count = buffer(27,4):uint()
          
          offset = 27 + 4
          local arg_content_len = 0
          for i = 1, arg_count do 
              arg_content_len = arg_content_len + buffer(offset,4):uint()
              offset = offset + 4
          end
          for i = 1, arg_count  do 
              arg_content_len = arg_content_len + buffer(offset,4):uint()
              offset = offset + 4
          end
          local req_prop_len = buffer(offset,4):uint()
          
          local len = 30 + arg_count*4*2 + 5 + service_name_len + method_name_len + arg_content_len + req_prop_len
          return len
        end
        -- response
        if op == 1 then
            local body_len = buffer(16, 4):uint()
            return 20 + body_len
        end
    end
end

-- create the dissection function
function hsf2_proto.dissector(buffer, pinfo, tree)
    
    -- check the protocol
    -- TODO support TB Remoting
    local check_proto = buffer(0, 1):uint()
    if check_proto < 12 or check_proto > 14 or check_proto == 13 then
        return
    end

    -- Set the protocol column
    pinfo.cols['protocol'] = "HSF2"

    -- 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 HSF2 protocol tree item
    local t_hsf2 = tree:add(hsf2_proto, buffer())
    local offset = 0

    local id = buffer(offset, 1):uint()
    offset = offset + 1
    t_hsf2:add(f_id, id)
    
    -- heart beat
    if id  == 12 then
        local op = buffer(offset, 1):uint()
        offset = offset + 1
        t_hsf2:add(f_op, op)

        -- Set the info column to the name of the function
        local info = vs_id[id]..":"..vs_op[op]
        pinfo.cols['info'] = info

        t_hsf2:add(f_version, buffer(offset, 1))
        offset = offset + 1
        t_hsf2:add(f_reserved, buffer(offset, 1))
        offset = offset + 1
        t_hsf2:add(f_reserved, buffer(offset, 1))
        offset = offset + 1
        t_hsf2:add(f_reserved, buffer(offset, 1))
        offset = offset + 1
        t_hsf2:add(f_req_id, buffer(offset, 8))
        offset = offset + 8
        t_hsf2:add(f_timeout, buffer(offset, 4))
    end
    -- TB REMOTING
    if id == 13 then
      -- TODO        
    end
    -- HSF REMOTING
    if id == 14 then        
        t_hsf2:add(f_version, buffer(offset, 1))
        offset = offset + 1
        local op = buffer(offset, 1):uint()
        offset = offset + 1
        t_hsf2:add(f_op, op)

        -- Set the info column to the name of the function
        local info = vs_id[id]..":"..vs_op[op]
        pinfo.cols['info'] = info

        -- request
        if op == 0 then
          t_hsf2:add(f_codectype, buffer(offset, 1))
          offset = offset + 1
          t_hsf2:add(f_reserved, buffer(offset, 1))
          offset = offset + 1
          t_hsf2:add(f_reserved, buffer(offset, 1))
          offset = offset + 1
          t_hsf2:add(f_reserved, buffer(offset, 1))
          offset = offset + 1
          t_hsf2:add(f_req_id, buffer(offset, 8))
          offset = offset + 8
          t_hsf2:add(f_timeout, buffer(offset, 4))
          offset = offset + 4

          local service_name_len = buffer(offset, 4):uint()
          t_hsf2:add(f_service_name_len, service_name_len)
          offset = offset +  4

          local method_name_len = buffer(offset,4):uint()
          t_hsf2:add(f_method_name_len, method_name_len)
          offset = offset +  4

          local arg_count = buffer(offset,4):uint()
          t_hsf2:add(f_arg_count, arg_count)
          offset = offset +  4
          
          local arg_type_len_array = {}
          for i = 1, arg_count do
              arg_type_len_array[i] = buffer(offset, 4):uint();
              offset = offset +  4
              t_hsf2:add(f_arg_type_len, arg_type_len_array[i])
          end

          local arg_obj_len_array = {}
          for i = 1, arg_count do
              arg_obj_len_array[i] = buffer(offset, 4):uint();
              offset = offset +  4
              t_hsf2:add(f_arg_obj_len, arg_obj_len_array[i])
          end

          local prop_len = buffer(offset, 4):uint();
          offset = offset +  4
          t_hsf2:add(f_req_prop_len, prop_len)

          t_hsf2:add(f_service_name, buffer(offset, service_name_len))
          offset = offset +  service_name_len

          t_hsf2:add(f_method_name, buffer(offset, method_name_len))
          offset = offset +  method_name_len

          for i = 1, #arg_type_len_array do
              t_hsf2:add(f_arg_type, buffer(offset, arg_type_len_array[i]))
              offset = offset +  arg_type_len_array[i]
          end

          for i = 1, #arg_obj_len_array do
              t_hsf2:add(f_arg_obj, buffer(offset, arg_obj_len_array[i]))
              offset = offset +  arg_obj_len_array[i]
          end

          if prop_len > 0 then
              t_hsf2:add(f_req_prop, buffer(offset, prop_len))
          end

        end

        -- response
        if op == 1 then
            t_hsf2:add(f_response_status, buffer(offset, 1))
            offset = offset + 1
            t_hsf2:add(f_codectype, buffer(offset, 1))
            offset = offset + 1
            t_hsf2:add(f_reserved, buffer(offset, 1))
            offset = offset + 1
            t_hsf2:add(f_reserved, buffer(offset, 1))
            offset = offset + 1
            t_hsf2:add(f_reserved, buffer(offset, 1))
            offset = offset + 1
            t_hsf2:add(f_req_id, buffer(offset, 8))
            offset = offset +  8

            local body_len = buffer(offset, 4):uint()
            t_hsf2:add(f_response_body_len, body_len)
            offset = offset +  4

            t_hsf2:add(f_response_body, buffer(offset, body_len))
        end
    end
end

-- load the tcp port table
tcp_table = DissectorTable.get("tcp.port")
-- register the protocol to port 12200
tcp_table:add(12200, hsf2_proto)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-12-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档