ネットワークパケットキャプチャで学ぶ TCP 3ウェイハンドシェイク
この記事の内容
- ICMPとTCPの接続確立方式の違いについて解説します
netstatコマンドを使ってリッスン状態のポートとESTABLISHED接続を確認します- WiresharkでSYNフラグをフィルタリングし、3ウェイハンドシェイクのパケットを観察します
- 送信元・送信先のIPアドレスとポート番号の4つの要素でTCP接続を識別する仕組みを説明します
- WiresharkのTCPストリーム追跡機能を使った接続トラブルシューティングの方法を紹介します
ICMPとTCPの違い
前回の動画では、Wiresharkを使ってICMPパケット(pingコマンド)の動きを確認しました。ICMPはリクエストを投げて返ってきたら「届いた」、返ってこなければ「届かなかった」というシンプルな仕組みです。接続を「確立する」という概念がありません。
一方、TCP(Transmission Control Protocol) はきちんと接続を確立するという手続きがあります。接続が確立されているかどうかを確認することが、ネットワークのトラブルシューティングにおいて非常に重要になります。
今回は、この接続確立の仕組みである3ウェイハンドシェイクをWiresharkで観察していきます。
環境の確認:リッスンしているポートの確認
まず、仮想マシン上で待ち受けているポートを確認します。
netstat -an
このコマンドを実行すると、現在リッスン(待ち受け)しているポートの一覧が表示されます。
LISTENING の状態にあるものが待ち受けているポートです。今回はこの中から 135番ポート に対してTCP接続を試みます。
Telnetのインストール
Telnetを使ってTCP接続を確認しますが、Windowsではデフォルトでインストールされていない場合があります。以下の手順でインストールします。
- 「Windowsの機能の有効化または無効化」 を開く (コントロールパネル → プログラム → プログラムと機能 → Windowsの機能の有効化または無効化)
- 一覧から 「Telnetクライアント」 にチェックを入れて有効化する
補足: 本番環境では telnet をインストールしてはいけないケースもあります。ネットワークのトラブルシューティング用として、初期セットアップ時に入れておくかどうかは運用ポリシーに従って判断してください。
Telnetで135番ポートへ接続する
今回の検証環境では、VM1のIPアドレスが 192.168.1.1、VM2のIPアドレスが 192.168.1.2 です。
VM1からVM2の135番ポートへtelnetで接続します。
telnet 192.168.1.2 135
黒い画面でカーソルが点滅している状態になれば、接続成功です。
ESTABLISHEDの確認
接続後、もう一度 netstat -an を実行すると、先ほどなかった ESTABLISHED の状態が確認できます。
netstat -an
VM1側でも確認すると、同じ接続が逆の視点で表示されます。
エフェメラルポートとは
ここで重要な概念を確認します。接続先のポート(135番)は意識しやすいのですが、接続元のポート番号を見落としがちです。
上の例では 50029 がVM1の接続元ポート番号です。このポートは接続のたびにランダムに割り当てられる**エフェメラルポート(一時的なポート)**と呼ばれます。
同じ相手に2本目の接続を張ると、別の一時ポートが使われます。
TCP接続を識別する4つの要素
2本の接続が混在しても通信が混ざらない理由は、TCP接続が以下の4つの要素の組み合わせで一意に識別されているためです。
| 要素 | 例 |
|---|---|
| 送信元IPアドレス | 192.168.1.1 |
| 送信元ポート番号 | 50029 |
| 送信先IPアドレス | 192.168.1.2 |
| 送信先ポート番号 | 135 |
この4つがすべて一致して初めて、同一のTCP接続として扱われます。
WiresharkでSYNパケットをフィルタリングする
TCPでは最初の接続要求としてSYN(Synchronize)フラグが立ったパケットが送出されます。Wiresharkで以下のフィルタを入力すると、接続開始のパケットだけを抜き出すことができます。
フィルタを適用すると、以下のようなパケットが表示されます。
SYNフラグはTCPヘッダーの中のフラグフィールドにセットされており、「これから接続を開始します」という合図です。
3ウェイハンドシェイクの流れ
3ウェイハンドシェイクは以下の3つのパケットのやり取りで接続を確立します。
- SYN:VM1 → VM2 「接続させてください」
- SYN-ACK:VM2 → VM1 「了解しました。こちらも接続をどうぞ」
- ACK:VM1 → VM2 「確認しました。接続確立します」
この3つのパケットがやり取りされると、netstat 上でその接続が ESTABLISHED の状態になります。
WiresharkのTCPストリーム追跡機能
特定のTCP接続の通信内容だけを追いたい場合は、WiresharkのTCPストリーム追跡機能を使います。
- SYNパケットなど、対象の接続のパケットを1つ右クリック
- 「追跡」→「TCPストリーム」 を選択
すると、その接続(4つの要素が一致するもの)のパケットだけがフィルタリングされ、一連の通信の流れをまとめて確認できるようになります。フィルタ条件は自動的に以下のような形式で設定されます。
この機能を使えば、大量のパケットが混在している中から、調査したい1つのTCPコネクションだけを素早く取り出すことができます。
接続トラブルシューティングへの応用
ネットワークの問題を調査するとき、まず確認すべきことを整理すると次のようになります。
netstat -anで待ち受け確認 そもそも接続先のポートがLISTENING状態にあるか確認するSYNパケットが飛んでいるか確認 Wiresharkで
tcp.flags.syn == 1フィルタを使い、接続要求が出ているかを確認するSYN-ACKが返ってきているか確認 相手からの応答(SYN-ACK)が届いているかを確認する
最後のACKが届いているか確認 3ウェイハンドシェイクが完成しているか確認する
3ウェイハンドシェイクが完了していない場合は、ファイアウォールの設定、ポート番号の誤り、ネットワーク経路の問題などが原因として考えられます。逆に接続は確立できているのに期待する動作にならない場合は、アプリケーションレイヤーの問題として切り分けることができます。
この「接続が確立できているかどうか」を早期に確認できるかどうかが、トラブルシューティングの速度に大きく影響します。
まとめ
今回はWiresharkを使ってTCPの3ウェイハンドシェイクを実際に観察しました。
- ICMPと異なり、TCPはSYN → SYN-ACK → ACKの3つのパケットで接続を確立します
netstat -anでリッスン中のポートやESTABLISHED接続を確認できます- TCP接続は送信元IP・送信元ポート・送信先IP・送信先ポートの4要素で一意に識別されます
- Wiresharkの
tcp.flags.syn == 1フィルタでSYNパケットを素早く抜き出せます - TCPストリーム追跡機能を使うと、特定の1接続のやり取りだけを絞り込んで確認できます
次回は、3ウェイハンドシェイクで接続が確立した後、Webサーバーとの通信でどのようなパケットがやり取りされるかをHTTPプロトコルレベルで観察する予定です。