パケットキャプチャの読み方 (概念)
一言でいうと
パケットキャプチャは、「誰が嘘をついているのか」を見極める最後の審判です。ただしこのラボ環境ではキャプチャの権限がないため、読み方を概念として身につけ、ラボはssと/proc/netで代用します。
なぜ必要なのか
ログはアプリケーションの主張であり、ssはカーネルの要約です。どちらも「パケットが実際にどう行き来したのか」を直接見せてはくれません。そのため、次の3つの状況では結局キャプチャが必要になります。
- 双方のログが食い違うとき(クライアントは送ったと言い、サーバーは受け取っていないと言う)
- 再送やフラグメンテーションのように、カーネルの中だけで起きることを見たいとき
- 中間装置(プロキシ、LB、NAT)が何かを書き換えていないか確認したいとき
どう動くのか
tcpdumpの必須オプションは、指で数えられるほどです。
tcpdump -nn -i any 'host 10.0.3.11 and tcp port 8080'
tcpdump -nn -i any 'icmp[icmptype] == 3 and icmp[icmpcode] == 4'
tcpdump -nn -i any -w /tmp/cap.pcap -c 2000
-nnはホスト名とポート名を解決しません。キャプチャ中にDNS問い合わせがまた出てしまう事故を防ぎます。-i anyはすべてのインターフェースを指します。コンテナ環境で特に役立ちます。-wでファイルに保存し、Wiresharkで開いて見ます。画面で読めるのは、おおまかな流れだけです。
読み方のコツの核心は、TCPフラグの表記です。
| 表記 | 意味 | このとき起きたこと |
|---|---|---|
[S] |
SYN | 接続の試行 |
[S.] |
SYN+ACK | 相手が受け入れました |
[.] |
ACK | データの確認 |
[P.] |
PSH+ACK | データの送信 |
[F.] |
FIN+ACK | 正常な終了の開始 |
[R] / [R.] |
RST | 拒否または強制終了 |
この表があれば、2種類の失敗が一目で分かれます。
- refused:
[S]が1つ出て、[R.]が1つ返って終わりです。2行で終わります。 - timeout: 同じシーケンスの
[S]が1秒、2秒、4秒の間隔で繰り返され、応答の行がそもそもありません。
MTUブラックホールの診断では、ICMPタイプ3コード4(Fragmentation needed)を捕まえてみます。「セキュリティのためにICMPはすべて塞ぐ」というポリシーが、それ自体で障害の要因になる理由がここにあります。塞いでよいのはecho request/replyくらいで、タイプ3コード4は必ず通さなければなりません。IPv6ではPacket Too Big(タイプ2)が同じ役割を果たし、こちらは選択の余地すらありません。
現場での姿
コンテナではキャプチャが難しいです。このラボ環境のようにcapabilityが取り除かれると、tcpdumpはソケットを開けません。Kubernetesなら、エフェメラルコンテナ(kubectl debug)で同じネットワーク名前空間に診断用Podをアタッチするのが標準的な回避策です。ノードに入れるなら、ノード上でPodのvethを指定してキャプチャします。
そのため、実務の手順はこう固まります。ssとcurl -wでできるだけ絞り込み、それでも2つの主張が食い違うときだけキャプチャを開きます。キャプチャは強力ですが、コストが高くつきます。
次にすること
このコースのラボは、すべてキャプチャなしで進めます。その代わり、/proc/net/tcpを直接読んで、カーネルが持っているソケットの状態を確認するステップがあります。キャプチャなしでカーネルの真実にいちばん近づける方法です。