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) 协议的解析。
+
+请求包的解析示例:
+
+
+
+响应包的解析示例:
+
+
+
+
+## 使用方式
+
+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`
+

+1. 可选,如需想使用相关字段进行过滤,可打开如下选项:
+ 
+
+上面提到的 "Personal Lua Plugins" 以及 "Personal configuration" 目录可查看 `About
Wireshark` 的 `Folders` 页面,相关目录是平台相关的,macOS 下如:
+
+
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:
+
+
+
+Example for the Echo response:
+
+
+
+
+## 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.
+

+1. Optional, turn on `Dissect Protobuf fields as Wireshark fields` if you want
to use related `baidu_std` fields for filtering:
+ 
+
+The "Personal Lua Plugins" and "Personal configuration" folders above can be
found under the `Folders` page of `About Wireshark`, for macOS:
+
+
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]