This is an automated email from the ASF dual-hosted git repository.

xiaofeng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new 12d07286 Add wireshark dissector for baidu_std protocol (#2408)
12d07286 is described below

commit 12d072862ebeb332245f900df95a10db1e219d78
Author: Xiaofeng Wang <[email protected]>
AuthorDate: Wed Oct 18 03:28:37 2023 +0800

    Add wireshark dissector for baidu_std protocol (#2408)
---
 docs/cn/wireshark_baidu_std.md                  |  27 +++
 docs/en/wireshark_baidu_std.md                  |  27 +++
 docs/images/wireshark_baidu_std_request.png     | Bin 0 -> 88216 bytes
 docs/images/wireshark_baidu_std_response.png    | Bin 0 -> 80784 bytes
 docs/images/wireshark_folders.png               | Bin 0 -> 119784 bytes
 docs/images/wireshark_protobuf_search_paths.png | Bin 0 -> 133530 bytes
 docs/images/wireshark_protobuf_settings.png     | Bin 0 -> 573273 bytes
 tools/wireshark_baidu_std.lua                   | 279 ++++++++++++++++++++++++
 8 files changed, 333 insertions(+)

diff --git a/docs/cn/wireshark_baidu_std.md b/docs/cn/wireshark_baidu_std.md
new file mode 100644
index 00000000..8dc7c4e6
--- /dev/null
+++ b/docs/cn/wireshark_baidu_std.md
@@ -0,0 +1,27 @@
+[English version](../en/wireshark_baidu_std.md)
+
+# 介绍
+
+`wireshark_baidu_std.lua` 是针对 [`baidu_std`](baidu_std.md) 协议的 `Wireshark` 
解析插件,同时支持 [`streaming_rpc`](streaming_rpc.md) 协议的解析。
+
+请求包的解析示例:
+
+![request](../images/wireshark_baidu_std_request.png)
+
+响应包的解析示例:
+
+![response](../images/wireshark_baidu_std_response.png)
+
+
+## 使用方式
+
+1. 将 [`wireshark_baidu_std.lua`](../../tools/wireshark_baidu_std.lua) 放到 
"Personal Lua Plugins" 目录下;
+1. 将 
[`options.proto`](../../src/brpc/options.proto)、[`streaming_rpc_meta.proto`](../../src/brpc/streaming_rpc_meta.proto)
 以及 [`baidu_rpc_meta.proto`](../../src/brpc/policy/baidu_rpc_meta.proto) 放到 
"Personal configuration" 目录下的 `protobuf` 目录中,目录如不存在可以手动创建;
+1. 参考 [Wireshark 
Protobuf](https://wiki.wireshark.org/Protobuf#protobuf-search-paths-settings) 
配置 `Protobuf` 系统 proto 文件路经,如:`/opt/homebrew/opt/protobuf/include`
+   
![wireshark-protobuf-search-paths](../images/wireshark_protobuf_search_paths.png)
+1. 可选,如需想使用相关字段进行过滤,可打开如下选项:
+   ![wireshark-protobuf-settings](../images/wireshark_protobuf_settings.png)
+
+上面提到的 "Personal Lua Plugins" 以及 "Personal configuration" 目录可查看 `About 
Wireshark` 的 `Folders` 页面,相关目录是平台相关的,macOS 下如:
+
+![About Wireshark](../images/wireshark_folders.png)
diff --git a/docs/en/wireshark_baidu_std.md b/docs/en/wireshark_baidu_std.md
new file mode 100644
index 00000000..af6a5118
--- /dev/null
+++ b/docs/en/wireshark_baidu_std.md
@@ -0,0 +1,27 @@
+[中文版](../cn/wireshark_baidu_std.md)
+
+# Overview
+
+`wireshark_baidu_std.lua` is a Wireshark Lua dissector written for 
[`baidu_std`](../cn/baidu_std.md) protocol, including the 
[`streaming_rpc`](streaming_rpc.md) protocol.
+
+Example for the Echo request:
+
+![request](../images/wireshark_baidu_std_request.png)
+
+Example for the Echo response:
+
+![response](../images/wireshark_baidu_std_response.png)
+
+
+## How to use
+
+1. Put [`wireshark_baidu_std.lua`](../../tools/wireshark_baidu_std.lua) under 
"Personal Lua Plugins";
+1. And put [`options.proto`](../../src/brpc/options.proto), 
[`streaming_rpc_meta.proto`](../../src/brpc/streaming_rpc_meta.proto) and 
[`baidu_rpc_meta.proto`](../../src/brpc/policy/baidu_rpc_meta.proto) in 
`protobuf` directory under "Personal configuration", create if not exist;
+1. Set `Protobuf Search Paths` for Protobuf official library include 
directory(e.g. `/opt/homebrew/opt/protobuf/include`), see [Wireshark 
Protobuf](https://wiki.wireshark.org/Protobuf#protobuf-search-paths-settings) 
for more details.
+   
![wireshark-protobuf-search-paths](../images/wireshark_protobuf_search_paths.png)
+1. Optional, turn on `Dissect Protobuf fields as Wireshark fields` if you want 
to use related `baidu_std` fields for filtering:
+   ![wireshark-protobuf-settings](../images/wireshark_protobuf_settings.png)
+
+The "Personal Lua Plugins" and "Personal configuration" folders above can be 
found under the `Folders` page of `About Wireshark`, for macOS:
+
+![About Wireshark](../images/wireshark_folders.png)
diff --git a/docs/images/wireshark_baidu_std_request.png 
b/docs/images/wireshark_baidu_std_request.png
new file mode 100644
index 00000000..0c6bc9c4
Binary files /dev/null and b/docs/images/wireshark_baidu_std_request.png differ
diff --git a/docs/images/wireshark_baidu_std_response.png 
b/docs/images/wireshark_baidu_std_response.png
new file mode 100644
index 00000000..b7180afa
Binary files /dev/null and b/docs/images/wireshark_baidu_std_response.png differ
diff --git a/docs/images/wireshark_folders.png 
b/docs/images/wireshark_folders.png
new file mode 100644
index 00000000..4b76a7a1
Binary files /dev/null and b/docs/images/wireshark_folders.png differ
diff --git a/docs/images/wireshark_protobuf_search_paths.png 
b/docs/images/wireshark_protobuf_search_paths.png
new file mode 100644
index 00000000..61cd1a53
Binary files /dev/null and b/docs/images/wireshark_protobuf_search_paths.png 
differ
diff --git a/docs/images/wireshark_protobuf_settings.png 
b/docs/images/wireshark_protobuf_settings.png
new file mode 100644
index 00000000..8d8aa1ca
Binary files /dev/null and b/docs/images/wireshark_protobuf_settings.png differ
diff --git a/tools/wireshark_baidu_std.lua b/tools/wireshark_baidu_std.lua
new file mode 100644
index 00000000..f166b7ca
--- /dev/null
+++ b/tools/wireshark_baidu_std.lua
@@ -0,0 +1,279 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+--------------------------------------------------------------------------------
+--  function
+--  Proto.new(name, desc)
+--  proto.dissector
+--  proto.fields
+--  proto.prefs
+--  proto.prefs_changed
+--  proto.init
+--  proto.name
+--  proto.description
+--------------------------------------------------------------------------------
+
+local plugin_info = {
+  name = "baidu",
+  version = "0.1.0",
+  description = "baidu_std"
+}
+
+local major, minor, patch = get_version():match("(%d+)%.(%d+)%.(%d+)")
+local version_code = tonumber(major) * 1000 * 1000 + tonumber(minor) * 1000 + 
tonumber(patch)
+
+local proto = Proto.new(plugin_info.name, plugin_info.description)
+
+local LM_DBG = function(fmt, ...)
+  if (tonumber(major) < 3) then
+    critical(table.concat({ plugin_info.name:upper() .. ":", fmt }, ' 
'):format(...))
+  else
+    print   (table.concat({ plugin_info.name:upper() .. ":", fmt }, ' 
'):format(...))
+  end
+end
+
+LM_DBG("Wireshark version =", get_version())
+LM_DBG("Lua version =", _VERSION)
+
+--------------------------------------------------------------------------------
+
+local MAGIC_CODE_PRPC = "PRPC"
+local MAGIC_CODE_STRM = "STRM"
+
+local PROTO_HEADER_LENGTH = 12
+
+
+local pf_magic     = ProtoField.string(plugin_info.name .. ".magic",
+                                       "Magic Code", BASE_NONE)
+local pf_body_size = ProtoField.uint32(plugin_info.name .. ".body_size",
+                                       "Body Size", BASE_DEC)
+local pf_meta_size = ProtoField.uint32(plugin_info.name .. ".meta_size",
+                                       "Meta Size", BASE_DEC)
+
+-- used to customize tree item
+local pf_any       = ProtoField.bytes (plugin_info.name .. ".any",
+                                       "Any", BASE_NONE)
+
+proto.fields = {
+  pf_magic,
+  pf_body_size,
+  pf_meta_size,
+  pf_any
+}
+
+----------------------------------------
+-- ref fields
+local proto_f_magic_code = Field.new(plugin_info.name .. ".magic")
+local proto_f_body_size  = Field.new(plugin_info.name .. ".body_size")
+local proto_f_meta_size  = Field.new(plugin_info.name .. ".meta_size")
+
+local proto_f_protobuf_field_name  = Field.new("protobuf.field.name")
+local proto_f_protobuf_field_value = Field.new("protobuf.field.value")
+
+----------------------------------------
+-- protobuf dissector
+-- Note:
+--   options.proto, baidu_rpc_meta.proto and streaming_rpc_meta.proto
+--   should be put in Wireshark Protobuf Search Paths.
+local protobuf_dissector = Dissector.get("protobuf")
+
+----------------------------------------
+-- declare functions
+
+local check_length  = function() end
+local dissect_proto = function() end
+
+----------------------------------------
+-- main dissector
+function proto.dissector(tvbuf, pktinfo, root)
+    local pktlen = tvbuf:len()
+
+    local bytes_consumed = 0
+
+    while bytes_consumed < pktlen do
+        local result = dissect_proto(tvbuf, pktinfo, root, bytes_consumed)
+
+        if result > 0 then
+            bytes_consumed = bytes_consumed + result
+        elseif result == 0 then
+            -- hit an error
+            return 0
+        else
+            pktinfo.desegment_offset = bytes_consumed
+            -- require more bytes
+            pktinfo.desegment_len = -result
+
+            return pktlen
+        end
+    end
+
+    return bytes_consumed
+end
+
+--------------------------------------------------------------------------------
+-- heuristic
+local function heur_dissect_proto(tvbuf, pktinfo, root)
+    LM_DBG("heur brpc: pkg number: " .. pktinfo.number)
+    if (tvbuf:len() < PROTO_HEADER_LENGTH) then
+        LM_DBG("too short: pkg number: " .. pktinfo.number)
+        return false
+    end
+
+    local magic = tvbuf:range(0, 4):string()
+    -- for range dissectors
+    if magic ~= MAGIC_CODE_PRPC and maigc ~= MAGIC_CODE_STRM then
+        LM_DBG("invalid magic code: pkg number: " .. pktinfo.number)
+        return false
+    end
+
+    proto.dissector(tvbuf, pktinfo, root)
+
+    pktinfo.conversation = proto
+
+    return true
+end
+proto:register_heuristic("tcp", heur_dissect_proto)
+
+--------------------------------------------------------------------------------
+
+local correlation_method_map = {}
+
+local store_method = function(correlation_id, method)
+    -- TODO: pop items
+    correlation_method_map[correlation_id] = method
+end
+
+local load_method = function(correlation_id)
+    return correlation_method_map[correlation_id]
+end
+
+-- check packet length, return length of packet if valid
+check_length = function(tvbuf, offset)
+    local msglen = tvbuf:len() - offset
+
+    if msglen ~= tvbuf:reported_length_remaining(offset) then
+        -- captured packets are being sliced/cut-off, so don't try to 
desegment/reassemble
+        LM_WARN("Captured packet was shorter than original, can't reassemble")
+        return 0
+    end
+
+    if msglen < PROTO_HEADER_LENGTH then
+        -- we need more bytes, so tell the main dissector function that we
+        -- didn't dissect anything, and we need an unknown number of more
+        -- bytes (which is what "DESEGMENT_ONE_MORE_SEGMENT" is used for)
+        return -DESEGMENT_ONE_MORE_SEGMENT
+    end
+
+    -- if we got here, then we know we have enough bytes in the Tvb buffer
+    -- to at least figure out whether this is valid baidu_std packet
+
+    local magic = tvbuf:range(offset, 4):string()
+    if magic ~= MAGIC_CODE_PRPC and magic ~= MAGIC_CODE_STRM then
+        return 0
+    end
+
+    -- big endian
+    local packet_size = tvbuf:range(offset+4, 4):uint() + PROTO_HEADER_LENGTH
+    if msglen < packet_size then
+        LM_DBG("Need more bytes to desegment full baidu_std packet")
+        return -(packet_size - msglen)
+    end
+
+    return packet_size
+end
+
+----------------------------------------
+dissect_proto = function(tvbuf, pktinfo, root, offset)
+    local len = check_length(tvbuf, offset)
+    if len <= 0 then
+        return len
+    end
+
+    local tree = root:add(proto, tvbuf:range(offset, len))
+
+    tree:add(pf_magic,     tvbuf:range(offset,   4))
+    tree:add(pf_body_size, tvbuf:range(offset+4, 4))
+    tree:add(pf_meta_size, tvbuf:range(offset+8, 4))
+
+    local meta_size = proto_f_meta_size().value
+    local body_size = proto_f_body_size().value
+    local tvb_meta = tvbuf:range(offset + PROTO_HEADER_LENGTH, meta_size):tvb()
+    if     proto_f_magic_code().value == MAGIC_CODE_PRPC then
+        -- dissect rpc meta fields
+        pktinfo.private["pb_msg_type"] = "message,brpc.policy.RpcMeta"
+        protobuf_dissector:call(tvb_meta, pktinfo, tree)
+
+        local direction, method
+
+        local service_name, method_name, correlation_id
+
+        -- 
https://ask.wireshark.org/question/31800/protobuf-dissector-with-nested-structures/?answer=31924#post-id-31924
+        local protobuf_field_names  = { proto_f_protobuf_field_name() }
+        local protobuf_field_values = { proto_f_protobuf_field_value() }
+        for k, v in pairs(protobuf_field_names) do
+            if     v.value == "request" then
+                direction = "request"
+            elseif v.value == "response" then
+                direction = "response"
+            elseif v.value == "service_name" then
+                service_name = protobuf_field_values[k].range:string(ENC_UTF8)
+            elseif v.value == "method_name" then
+                method_name = protobuf_field_values[k].range:string(ENC_UTF8)
+            elseif v.value == "correlation_id" then
+                correlation_id = protobuf_field_values[k].range:uint64()
+            end
+        end
+
+        if     direction == "request" then
+            method = service_name .. "/" .. method_name
+            -- NOTE: convert uint64 to string to be used as key of table
+            store_method(tostring(correlation_id), method)
+        elseif direction == "response" then
+            method = load_method(tostring(correlation_id))
+        end
+
+        if method ~= nil then
+            -- dissect rpc body
+            local tvb_body = tvbuf:range(offset + PROTO_HEADER_LENGTH + 
meta_size, body_size - meta_size):tvb()
+            pktinfo.private["pb_msg_type"] = "application/grpc,/" .. method .. 
"," .. direction
+            protobuf_dissector:call(tvb_body, pktinfo, tree)
+        end
+    elseif proto_f_magic_code().value == MAGIC_CODE_STRM then
+        -- dissect streaming meta fields
+        pktinfo.private["pb_msg_type"] = "message,brpc.StreamFrameMeta"
+        protobuf_dissector:call(tvb_meta, pktinfo, tree)
+    end
+
+    -- body fields are business related, customized here
+
+    return len
+end
+
+--------------------------------------------------------------------------------
+-- Editor modelines
+--
+-- Local variables:
+-- c-basic-offset: 4
+-- tab-width: 4
+-- indent-tab-mode: nil
+-- End:
+--
+-- kate: indent-width 4; tab-width 4;
+-- vim: tabstop=4:softtabstop=4:shiftwidth=4:expandtab
+-- :indentSize=4:tabSize=4:noTabs=true


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to