作者:Huang Qiangxiong和Patrice Chalin
Wireshark[1]是一个开放源码的网络协议分析器,可以用于协议开发、网络故障排除和教育。Wireshark可以分析在网络上传输的gRPC消息,并了解这些消息的二进制格式。
在这篇文章中,你将学习如何配置和使用Wireshark的gRPC解剖器[2]和Protocol Buffers (Protobuf)解剖器[3],它们是特定于协议的组件,允许你用Wireshark分析gRPC消息。
特性
gRPC和Protobuf解剖器的主要特性如下:
- 支持解析(解码)以协议缓冲线格式[4]或JSON序列化的gRPC消息
- 支持解析gRPC一元消息、服务器流、客户端流和双向流RPC调用
- 增强了对序列化协议缓冲区数据的剖析,允许你做以下操作:
- 加载相关的.proto文件
- 为字节或字符串类型的协议缓冲区字段注册自己的子解剖器
捕获gRPC流量
这篇文章的重点是分析捕获的gRPC消息。如果需要了解如何在捕获文件中保存网络流量,请参见《Wireshark用户指南》[5]中的捕获实时网络数据[6]。
请注意 目前,Wireshark只能解析gRPC纯文本消息。虽然Wireshark支持TLS解析[7],但它需要每个会话的密钥。在撰写本文时,Go gRPC支持导出这样的键。要学习如何使用Go gRPC导出密钥,以及其他语言的支持,请参见如何导出gRPC的TLS主密钥[8]。
例子
让我们通过必要的设置来分析以前捕获的消息,这些消息是由协议缓冲区教程[9]中使用的address book应用程序的略微扩展版本生成的。
Address book .proto文件
应用程序的主要协议文件是addressbook.proto:
代码语言:javascript复制syntax = "proto3";
package tutorial;
import "google/protobuf/timestamp.proto";
message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phone = 4;
google.protobuf.Timestamp last_updated = 5;
bytes portrait_image = 6;
}
message AddressBook {
repeated Person people = 1;
}
这个文件与协议缓冲区教程版本[10]相同,除了附加的portrait_image字段之外。
请注意文件顶部的import语句,它用于导入时间戳,这是许多众所周知的协议缓冲区类型[11]之一。
我们的应用程序变体还定义了一个person-search服务,该服务可用于根据所选的Person属性搜索地址簿条目。服务定义在person_search_service.proto中:
代码语言:javascript复制syntax = "proto3";
package tutorial;
import "addressbook.proto";
message PersonSearchRequest {
repeated string name = 1;
repeated int32 id = 2;
repeated string phoneNumber = 3;
}
service PersonSearchService {
rpc Search (PersonSearchRequest) returns (stream Person) {}
}
因为服务使用在addressbook.proto中定义的Person类型,addressbook.proto在文件的开头被导入。
设置protobuf搜索路径
当Wireshark知道你正在分析的应用程序所使用的.proto文件时,它会给出最有意义的解码。
你可以在preferences > Protocols > Protobuf下Edit辑菜单中设置Protobuf的搜索路径,从而告诉Wireshark在哪里可以找到.proto文件。
如果我们的示例应用的.proto文件在d:/protos/my_proto_files目录下,而Protobuf库的官方目录是d:/protos/protobuf-3.4.1/include,那么将这两个路径添加为源目录,如下所示:

通过为应用程序的协议目录选择“Load all files”选项,你可以从addressbook.proto和person_search_service.proto文件中预加载消息定义。
加载捕获文件
在Wireshark的SampleCaptures页面[12]中,下载以下通过运行应用程序并发出搜索请求创建的示例gRPC捕获文件:grpc_person_search_protobuf_with_image.pcapng[13]。
在“File”菜单中选择“Open”,在Wireshark加载捕获文件。Wireshark在窗口顶部的包列表窗格中按顺序显示捕获文件中的所有网络流量。
在Packet-list面板中选择一个条目,Wireshark将对其进行解码,并在下方面板中显示其详细信息,如下所示:

从详细信息窗格中选择一个条目,查看与该条目对应的字节序列:

设置端口流量类型
app的服务器端端口是50051。客户端端口对于每个RPC调用都是不同的,在示例捕获文件中是51035。
你需要告诉Wireshark这些端口承载着HTTP2流量。通过Decode As对话框做到这一点,你可以从Analyze菜单(或从包列表窗格右键单击条目)访问该对话框。你只需要注册服务器端端口:

看看包列表窗格,你会看到Wireshark现在解码HTTP2和gRPC消息:

解码搜索请求消息
选择发送到端口50051的第一个gRPC消息,它对应于示例的服务请求消息。下面是Wireshark对gRPC请求的分析:

通过检查HTTP2消息头path字段,你将看到应用程序服务的URL(/tutorial.PersonSearchService),后面是被调用的RPC(Search)的名称。
content-type是由gRPC库设置的,它通知Wireshark HTTP2消息的内容是gRPC消息。通过检查样本gRPC请求的解码协议缓冲区消息,可以看到搜索请求是关于名称“Jason”和“Lily”。
解码服务器流响应
由于Search RPC响应是服务器流,因此可以一个接一个地将Person对象返回给客户端。
选择响应流中返回的第二个Person消息,查看其详细信息:

通过注册子解剖器,你可以让Wireshark进一步解码类型为byte或string的字段。例如,要学习如何注册portrait_image字段的PNG解码器,请参阅Protobuf字段子解剖器[14]。
支持gRPC和协议缓冲区的历史
以下是Wireshark支持gRPC和协议缓冲区的版本注释列表:
- v2.6.0:gRPC和Protobuf解剖器的第一个版本,不支持.proto文件或流式RPC。
- v3.2.0:改进了基于.proto文件对序列化协议缓冲区数据的解析,并且支持流式RPC。
- v3.3.0:改进和增强了.proto文件支持,例如对协议缓冲区字段值的捕获文件搜索。
- v3.4.0:Protocol Buffers时间戳[15]时间显示为locale date-time字符串。
了解更多
想了解更多吗?从Wireshark用户指南[16]开始。关于本文中使用的示例的更多细节,以及其他包含gRPC消息的示例捕获文件,请参阅gRPC解剖器[17]和Protocol Buffers解剖器[18]wiki页面。
参考资料
[1]
Wireshark: https://www.wireshark.org/
[2]
gRPC解剖器: https://gitlab.com/wireshark/wireshark/-/wikis/gRPC
[3]
Protocol Buffers (Protobuf)解剖器: https://gitlab.com/wireshark/wireshark/-/wikis/Protobuf
[4]
协议缓冲线格式: https://developers.google.com/protocol-buffers/docs/encoding
[5]
《Wireshark用户指南》: https://www.wireshark.org/docs/wsug_html_chunked/
[6]
捕获实时网络数据: https://www.wireshark.org/docs/wsug_html_chunked/ChapterCapture.html
[7]
Wireshark支持TLS解析: https://gitlab.com/wireshark/wireshark/-/wikis/tls
[8]
如何导出gRPC的TLS主密钥: https://gitlab.com/wireshark/wireshark/-/wikis/How-to-Export-TLS-Master-keys-of-gRPC
[9]
协议缓冲区教程: https://developers.google.com/protocol-buffers/docs/tutorials
[10]
协议缓冲区教程版本: https://github.com/protocolbuffers/protobuf/blob/master/examples/addressbook.proto
[11]
众所周知的协议缓冲区类型: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf
[12]
SampleCaptures页面: https://gitlab.com/wireshark/wireshark/-/wikis/SampleCaptures
[13]
grpc_person_search_protobuf_with_image.pcapng: https://gitlab.com/wireshark/wireshark/-/wikis/uploads/f6fcdceb0248669c0b057bd15d45ab6f/grpc_person_search_protobuf_with_image.pcapng
[14]
Protobuf字段子解剖器: https://gitlab.com/wireshark/wireshark/-/wikis/Protobuf#protobuf-field-subdissectors
[15]
时间戳: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp
[16]
Wireshark用户指南: https://www.wireshark.org/docs/wsug_html_chunked/
[17]
gRPC解剖器: https://gitlab.com/wireshark/wireshark/-/wikis/gRPC
[18]
Protocol Buffers解剖器: https://gitlab.com/wireshark/wireshark/-/wikis/Protobuf


