ネットワークパケットキャプチャで学ぶ 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

このコマンドを実行すると、現在リッスン(待ち受け)しているポートの一覧が表示されます。

TTTCCCPPP000...000...000...000:::1453405540000...000...000...000:::000LLLIIISSSTTTEEENNNIIINNNGGG

LISTENING の状態にあるものが待ち受けているポートです。今回はこの中から 135番ポート に対してTCP接続を試みます。


Telnetのインストール

Telnetを使ってTCP接続を確認しますが、Windowsではデフォルトでインストールされていない場合があります。以下の手順でインストールします。

  1. 「Windowsの機能の有効化または無効化」 を開く (コントロールパネル → プログラム → プログラムと機能 → Windowsの機能の有効化または無効化)
  2. 一覧から 「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
TCP192.168.1.2:135192.168.1.1:50029ESTABLISHED

VM1側でも確認すると、同じ接続が逆の視点で表示されます。

TCP192.168.1.1:50029192.168.1.2:135ESTABLISHED

エフェメラルポートとは

ここで重要な概念を確認します。接続先のポート(135番)は意識しやすいのですが、接続元のポート番号を見落としがちです。

上の例では 50029 がVM1の接続元ポート番号です。このポートは接続のたびにランダムに割り当てられる**エフェメラルポート(一時的なポート)**と呼ばれます。

同じ相手に2本目の接続を張ると、別の一時ポートが使われます。

TCP192.168.1.1:50030192.168.1.2:135ESTABLISHED

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で以下のフィルタを入力すると、接続開始のパケットだけを抜き出すことができます。

tcp.flags.syn==1

フィルタを適用すると、以下のようなパケットが表示されます。

119922..116688..11..11::5500002390119922..116688..11..22::113355[[SSYYNN]]

SYNフラグはTCPヘッダーの中のフラグフィールドにセットされており、「これから接続を開始します」という合図です。


3ウェイハンドシェイクの流れ

3ウェイハンドシェイクは以下の3つのパケットのやり取りで接続を確立します。

  1. SYN:VM1 → VM2 「接続させてください」
  2. SYN-ACK:VM2 → VM1 「了解しました。こちらも接続をどうぞ」
  3. ACK:VM1 → VM2 「確認しました。接続確立します」

この3つのパケットがやり取りされると、netstat 上でその接続が ESTABLISHED の状態になります。


WiresharkのTCPストリーム追跡機能

特定のTCP接続の通信内容だけを追いたい場合は、WiresharkのTCPストリーム追跡機能を使います。

  1. SYNパケットなど、対象の接続のパケットを1つ右クリック
  2. 「追跡」→「TCPストリーム」 を選択

すると、その接続(4つの要素が一致するもの)のパケットだけがフィルタリングされ、一連の通信の流れをまとめて確認できるようになります。フィルタ条件は自動的に以下のような形式で設定されます。

tcp.streameq0

この機能を使えば、大量のパケットが混在している中から、調査したい1つのTCPコネクションだけを素早く取り出すことができます。


接続トラブルシューティングへの応用

ネットワークの問題を調査するとき、まず確認すべきことを整理すると次のようになります。

  1. netstat -an で待ち受け確認 そもそも接続先のポートが LISTENING 状態にあるか確認する

  2. SYNパケットが飛んでいるか確認 Wiresharkで tcp.flags.syn == 1 フィルタを使い、接続要求が出ているかを確認する

  3. SYN-ACKが返ってきているか確認 相手からの応答(SYN-ACK)が届いているかを確認する

  4. 最後の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プロトコルレベルで観察する予定です。