untitled weblog

とりとめのない学習メモです。主に Web システムの IT インフラに関することを書いてます。

gRPC の通信を tcpdump で取得して Wireshark で覗いてみた

はじめに

gRPC の Go の QuickStart チュートリアルをやった時の備忘 - untitled をやってみた流れで gRPC の通信を WireShark でキャプチャしてみました。

環境

以下を使います。 セットアップの方法については省略します。

tcpdump でのキャプチャ

TCP ダンプでキャプチャを開始します。

% sudo tcpdump -A -n -i lo -W /tmp/grpc-capture.dump

gRPCサーバーを起動します。

~/path/to/grpc-go/examples/helloworld/greeter_server ((v1.63.0)) % go run main.go
2024/08/29 02:12:36 server listening at [::]:50051

gRPCクライアントを起動します。

~/path/to/grpc-go/examples/helloworld/greeter_client ((v1.63.0)) % go run main.go
2024/08/29 02:15:57 Greeting: Hello world

Wireshark で読み込み

以下のようになっていました。

開始(Frame1-3)は 3ウェイハンドシェイクで始まり、FIN/ACK -> FIN/ACK -> ACK でクローズ(Frame18-20)しています。

Frame4-11 でMagic, SETTINGS, WINDOW_UPDATE, PING というフレームが送信されています。これらはHTTP2のものと思います。 間の Frame12,15 が gRPC のリクエスト、レスポンスのようです。

いくつかわかりやすいヘッダーを見てみます。 Content-Type が「application/grpc」で始まっていない場合、gRPC サーバーは HTTP ステータス 415 (サポートされていないメディア タイプ) で応答する必要があるとのことで、ここでは application/grpc になっていました。

User-Agent は必須ではないようですが、user-agent: grpc-go/1.63.0 となっていました。

Frame 12: 216 bytes on wire (1728 bits), 216 bytes captured (1728 bits)
    Encapsulation type: Ethernet (1)
    Arrival Time: Aug 29, 2024 11:15:57.925436000 JST
    UTC Arrival Time: Aug 29, 2024 02:15:57.925436000 UTC
    Epoch Arrival Time: 1724897757.925436000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 0.000108000 seconds]
    [Time delta from previous displayed frame: 0.000108000 seconds]
    [Time since reference or first frame: 0.000396000 seconds]
    Frame Number: 12
    Frame Length: 216 bytes (1728 bits)
    Capture Length: 216 bytes (1728 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: eth:ethertype:ipv6:tcp:http2:grpc:protobuf]
    [Coloring Rule Name: HTTP]
    [Coloring Rule String: http || tcp.port == 80 || http2]
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
    Destination: 00:00:00_00:00:00 (00:00:00:00:00:00)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Source: 00:00:00_00:00:00 (00:00:00:00:00:00)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Type: IPv6 (0x86dd)
    [Stream index: 0]
Internet Protocol Version 6, Src: ::1, Dst: ::1
    0110 .... = Version: 6
    .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
        .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
        .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
    .... 0001 1000 1010 0001 0110 = Flow Label: 0x18a16
    Payload Length: 162
    Next Header: TCP (6)
    Hop Limit: 64
    Source Address: ::1
        [Address Space: Reserved by IETF]
        [Special-Purpose Allocation: Loopback Address]
            [Source: False]
            [Destination: False]
            [Forwardable: False]
            [Globally Reachable: False]
            [Reserved-by-Protocol: True]
    Destination Address: ::1
        [Address Space: Reserved by IETF]
        [Special-Purpose Allocation: Loopback Address]
            [Source: False]
            [Destination: False]
            [Forwardable: False]
            [Globally Reachable: False]
            [Reserved-by-Protocol: True]
    [Stream index: 0]
Transmission Control Protocol, Src Port: 55646, Dst Port: 50051, Seq: 34, Ack: 25, Len: 130
    Source Port: 55646
    Destination Port: 50051
    [Stream index: 0]
    [Stream Packet Number: 12]
    [Conversation completeness: Complete, WITH_DATA (31)]
        ..0. .... = RST: Absent
        ...1 .... = FIN: Present
        .... 1... = Data: Present
        .... .1.. = ACK: Present
        .... ..1. = SYN-ACK: Present
        .... ...1 = SYN: Present
        [Completeness Flags: ·FDASS]
    [TCP Segment Len: 130]
    Sequence Number: 34    (relative sequence number)
    Sequence Number (raw): 3678708405
    [Next Sequence Number: 164    (relative sequence number)]
    Acknowledgment Number: 25    (relative ack number)
    Acknowledgment number (raw): 3438549865
    1000 .... = Header Length: 32 bytes (8)
    Flags: 0x018 (PSH, ACK)
        000. .... .... = Reserved: Not set
        ...0 .... .... = Accurate ECN: Not set
        .... 0... .... = Congestion Window Reduced: Not set
        .... .0.. .... = ECN-Echo: Not set
        .... ..0. .... = Urgent: Not set
        .... ...1 .... = Acknowledgment: Set
        .... .... 1... = Push: Set
        .... .... .0.. = Reset: Not set
        .... .... ..0. = Syn: Not set
        .... .... ...0 = Fin: Not set
        [TCP Flags: ·······AP···]
    Window: 512
    [Calculated window size: 65536]
    [Window size scaling factor: 128]
    Checksum: 0x00aa [unverified]
    [Checksum Status: Unverified]
    Urgent Pointer: 0
    Options: (12 bytes), No-Operation (NOP), No-Operation (NOP), Timestamps
        TCP Option - No-Operation (NOP)
            Kind: No-Operation (1)
        TCP Option - No-Operation (NOP)
            Kind: No-Operation (1)
        TCP Option - Timestamps: TSval 848634857, TSecr 848634857
            Kind: Time Stamp Option (8)
            Length: 10
            Timestamp value: 848634857
            Timestamp echo reply: 848634857
    [Timestamps]
        [Time since first frame in this TCP stream: 0.000396000 seconds]
        [Time since previous frame in this TCP stream: 0.000108000 seconds]
    [SEQ/ACK analysis]
        [iRTT: 0.000029000 seconds]
        [Bytes in flight: 130]
        [Bytes sent since last PSH flag: 130]
    TCP payload (130 bytes)
    [PDU Size: 9]
    [PDU Size: 100]
    [PDU Size: 21]
HyperText Transfer Protocol 2
    Stream: SETTINGS, Stream ID: 0, Length 0
        Length: 0
        Type: SETTINGS (4)
        Flags: 0x01, ACK
            0000 000. = Unused: 0x00
            .... ...1 = ACK: True
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
HyperText Transfer Protocol 2
    Stream: HEADERS, Stream ID: 1, Length 91, POST /helloworld.Greeter/SayHello
        Length: 91
        Type: HEADERS (1)
        Flags: 0x04, End Headers
            00.0 ..0. = Unused: 0x00
            ..0. .... = Priority: False
            .... 0... = Padded: False
            .... .1.. = End Headers: True
            .... ...0 = End Stream: False
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
        [Pad Length: 0]
        Header Block Fragment: 838645956272d141fc1eca245f15852a4b631b87eb1968a0ff418ba0e41d139d09b8d800d87f5f8b1d75d0620d263d4c4d65647a8a9acac8b4c7602bb8cae040027465864d833505b11f40899acac8b24d494f6a7f857df7c4d82d
        [Header Length: 225]
        [Header Count: 8]
        Header: :method: POST
            Name Length: 7
            Name: :method
            Value Length: 4
            Value: POST
            :method: POST
            [Unescaped: POST]
            Representation: Indexed Header Field
            Index: 3
        Header: :scheme: http
            Name Length: 7
            Name: :scheme
            Value Length: 4
            Value: http
            :scheme: http
            [Unescaped: http]
            Representation: Indexed Header Field
            Index: 6
        Header: :path: /helloworld.Greeter/SayHello
            Name Length: 5
            Name: :path
            Value Length: 28
            Value: /helloworld.Greeter/SayHello
            :path: /helloworld.Greeter/SayHello
            [Unescaped: /helloworld.Greeter/SayHello]
            Representation: Literal Header Field with Incremental Indexing - Indexed Name
            Index: 5
        Header: :authority: localhost:50051
            Name Length: 10
            Name: :authority
            Value Length: 15
            Value: localhost:50051
            :authority: localhost:50051
            [Unescaped: localhost:50051]
            Representation: Literal Header Field with Incremental Indexing - Indexed Name
            Index: 1
        Header: content-type: application/grpc
            Name Length: 12
            Name: content-type
            Value Length: 16
            Value: application/grpc
            content-type: application/grpc
            [Unescaped: application/grpc]
            Representation: Literal Header Field with Incremental Indexing - Indexed Name
            Index: 31
        Header: user-agent: grpc-go/1.63.0
            Name Length: 10
            Name: user-agent
            Value Length: 14
            Value: grpc-go/1.63.0
            user-agent: grpc-go/1.63.0
            [Unescaped: grpc-go/1.63.0]
            Representation: Literal Header Field with Incremental Indexing - Indexed Name
            Index: 58
        Header: te: trailers
            Name Length: 2
            Name: te
            Value Length: 8
            Value: trailers
            [Unescaped: trailers]
            Representation: Literal Header Field with Incremental Indexing - New Name
        Header: grpc-timeout: 999250u
            Name Length: 12
            Name: grpc-timeout
            Value Length: 7
            Value: 999250u
            [Unescaped: 999250u]
            Representation: Literal Header Field with Incremental Indexing - New Name
        [Full request URI: http://localhost:50051/helloworld.Greeter/SayHello]
        [Response in frame: 15]
HyperText Transfer Protocol 2
    Stream: DATA, Stream ID: 1, Length 12
        Length: 12
        Type: DATA (0)
        Flags: 0x01, End Stream
            0000 .00. = Unused: 0x00
            .... 0... = Padded: False
            .... ...1 = End Stream: True
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
        [Pad Length: 0]
        DATA payload (12 bytes)
        [Connection window size (before): 65535]
        [Connection window size (after): 65523]
        [Stream window size (before): 65535]
        [Stream window size (after): 65523]
GRPC Message: /helloworld.Greeter/SayHello, Request
    0... .... = Frame Type: Data (0)
    .... ...0 = Compressed Flag: Not Compressed (0)
    Message Length: 7
    Message Data: 7 bytes
Protocol Buffers: /helloworld.Greeter/SayHello,request
    Message: <UNKNOWN>
        Field(1):
            [Field Name: <UNKNOWN>]
            .000 1... = Field Number: 1
            .... .010 = Wire Type: Length-delimited (2)
            Value Length: 5
            Value: 776f726c64
Frame 15: 169 bytes on wire (1352 bits), 169 bytes captured (1352 bits)
    Encapsulation type: Ethernet (1)
    Arrival Time: Aug 29, 2024 11:15:57.925722000 JST
    UTC Arrival Time: Aug 29, 2024 02:15:57.925722000 UTC
    Epoch Arrival Time: 1724897757.925722000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 0.000122000 seconds]
    [Time delta from previous displayed frame: 0.000122000 seconds]
    [Time since reference or first frame: 0.000682000 seconds]
    Frame Number: 15
    Frame Length: 169 bytes (1352 bits)
    Capture Length: 169 bytes (1352 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: eth:ethertype:ipv6:tcp:http2:grpc:protobuf]
    [Coloring Rule Name: HTTP]
    [Coloring Rule String: http || tcp.port == 80 || http2]
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
    Destination: 00:00:00_00:00:00 (00:00:00:00:00:00)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Source: 00:00:00_00:00:00 (00:00:00:00:00:00)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Type: IPv6 (0x86dd)
    [Stream index: 0]
Internet Protocol Version 6, Src: ::1, Dst: ::1
    0110 .... = Version: 6
    .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
        .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
        .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
    .... 0101 0111 1001 1101 0100 = Flow Label: 0x579d4
    Payload Length: 115
    Next Header: TCP (6)
    Hop Limit: 64
    Source Address: ::1
        [Address Space: Reserved by IETF]
        [Special-Purpose Allocation: Loopback Address]
            [Source: False]
            [Destination: False]
            [Forwardable: False]
            [Globally Reachable: False]
            [Reserved-by-Protocol: True]
    Destination Address: ::1
        [Address Space: Reserved by IETF]
        [Special-Purpose Allocation: Loopback Address]
            [Source: False]
            [Destination: False]
            [Forwardable: False]
            [Globally Reachable: False]
            [Reserved-by-Protocol: True]
    [Stream index: 0]
Transmission Control Protocol, Src Port: 50051, Dst Port: 55646, Seq: 55, Ack: 181, Len: 83
    Source Port: 50051
    Destination Port: 55646
    [Stream index: 0]
    [Stream Packet Number: 15]
    [Conversation completeness: Complete, WITH_DATA (31)]
        ..0. .... = RST: Absent
        ...1 .... = FIN: Present
        .... 1... = Data: Present
        .... .1.. = ACK: Present
        .... ..1. = SYN-ACK: Present
        .... ...1 = SYN: Present
        [Completeness Flags: ·FDASS]
    [TCP Segment Len: 83]
    Sequence Number: 55    (relative sequence number)
    Sequence Number (raw): 3438549895
    [Next Sequence Number: 138    (relative sequence number)]
    Acknowledgment Number: 181    (relative ack number)
    Acknowledgment number (raw): 3678708552
    1000 .... = Header Length: 32 bytes (8)
    Flags: 0x018 (PSH, ACK)
        000. .... .... = Reserved: Not set
        ...0 .... .... = Accurate ECN: Not set
        .... 0... .... = Congestion Window Reduced: Not set
        .... .0.. .... = ECN-Echo: Not set
        .... ..0. .... = Urgent: Not set
        .... ...1 .... = Acknowledgment: Set
        .... .... 1... = Push: Set
        .... .... .0.. = Reset: Not set
        .... .... ..0. = Syn: Not set
        .... .... ...0 = Fin: Not set
        [TCP Flags: ·······AP···]
    Window: 512
    [Calculated window size: 65536]
    [Window size scaling factor: 128]
    Checksum: 0x007b [unverified]
    [Checksum Status: Unverified]
    Urgent Pointer: 0
    Options: (12 bytes), No-Operation (NOP), No-Operation (NOP), Timestamps
        TCP Option - No-Operation (NOP)
            Kind: No-Operation (1)
        TCP Option - No-Operation (NOP)
            Kind: No-Operation (1)
        TCP Option - Timestamps: TSval 848634858, TSecr 848634858
            Kind: Time Stamp Option (8)
            Length: 10
            Timestamp value: 848634858
            Timestamp echo reply: 848634858
    [Timestamps]
        [Time since first frame in this TCP stream: 0.000682000 seconds]
        [Time since previous frame in this TCP stream: 0.000122000 seconds]
    [SEQ/ACK analysis]
        [This is an ACK to the segment in frame: 14]
        [The RTT to ACK the segment was: 0.000122000 seconds]
        [iRTT: 0.000029000 seconds]
        [Bytes in flight: 83]
        [Bytes sent since last PSH flag: 83]
    TCP payload (83 bytes)
    [PDU Size: 23]
    [PDU Size: 27]
    [PDU Size: 33]
HyperText Transfer Protocol 2
    Stream: HEADERS, Stream ID: 1, Length 14, 200 OK
        Length: 14
        Type: HEADERS (1)
        Flags: 0x04, End Headers
            00.0 ..0. = Unused: 0x00
            ..0. .... = Priority: False
            .... 0... = Padded: False
            .... .1.. = End Headers: True
            .... ...0 = End Stream: False
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
        [Pad Length: 0]
        Header Block Fragment: 885f8b1d75d0620d263d4c4d6564
        [Header Length: 54]
        [Header Count: 2]
        Header: :status: 200 OK
            Name Length: 7
            Name: :status
            Value Length: 3
            Value: 200
            :status: 200
            [Unescaped: 200]
            Representation: Indexed Header Field
            Index: 8
        Header: content-type: application/grpc
            Name Length: 12
            Name: content-type
            Value Length: 16
            Value: application/grpc
            content-type: application/grpc
            [Unescaped: application/grpc]
            Representation: Literal Header Field with Incremental Indexing - Indexed Name
            Index: 31
        [Time since request: 0.000286000 seconds]
        [Request in frame: 12]
HyperText Transfer Protocol 2
    Stream: DATA, Stream ID: 1, Length 18
        Length: 18
        Type: DATA (0)
        Flags: 0x00
            0000 .00. = Unused: 0x00
            .... 0... = Padded: False
            .... ...0 = End Stream: False
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
        [Pad Length: 0]
        DATA payload (18 bytes)
        [Connection window size (before): 65535]
        [Connection window size (after): 65517]
        [Stream window size (before): 65535]
        [Stream window size (after): 65517]
GRPC Message: /helloworld.Greeter/SayHello, Response
    0... .... = Frame Type: Data (0)
    .... ...0 = Compressed Flag: Not Compressed (0)
    Message Length: 13
    Message Data: 13 bytes
Protocol Buffers: /helloworld.Greeter/SayHello,response
    Message: <UNKNOWN>
        Field(1):
            [Field Name: <UNKNOWN>]
            .000 1... = Field Number: 1
            .... .010 = Wire Type: Length-delimited (2)
            Value Length: 11
            Value: 48656c6c6f20776f726c64
HyperText Transfer Protocol 2
    Stream: HEADERS, Stream ID: 1, Length 24
        Length: 24
        Type: HEADERS (1)
        Flags: 0x05, End Headers, End Stream
            00.0 ..0. = Unused: 0x00
            ..0. .... = Priority: False
            .... 0... = Padded: False
            .... .1.. = End Headers: True
            .... ...1 = End Stream: True
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
        [Pad Length: 0]
        Header Block Fragment: 40889acac8b21234da8f013040899acac8b5254207317f00
        [Header Length: 40]
        [Header Count: 2]
        Header: grpc-status: 0
            Name Length: 11
            Name: grpc-status
            Value Length: 1
            Value: 0
            [Unescaped: 0]
            Representation: Literal Header Field with Incremental Indexing - New Name
        Header: grpc-message: 
            Name Length: 12
            Name: grpc-message
            Value Length: 0
            Value: 
            [Unescaped: ]
            Representation: Literal Header Field with Incremental Indexing - New Name
        [Time since request: 0.000286000 seconds]
        [Request in frame: 12]

まとめ

gRPC の通信を tcpdump で取得して Wireshark で覗いてみました。 HTTP2 の元で動く gRPC の通信の流れがなんとなくつかめました。

参考