-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add wireshark dissector for baidu_std protocol (#2408)
- Loading branch information
Showing
8 changed files
with
333 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |