使用Wireshark分析gRPC消息

2021-03-15 17:04:14 浏览数 (5)

作者: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

0 人点赞