TCPスリーウェイハンドシェイク詳細(RFC 793準拠)

Tech

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

TCPスリーウェイハンドシェイク詳細(RFC 793準拠)

背景

インターネット通信の根幹をなすTransmission Control Protocol (TCP) は、信頼性の高いデータ転送を実現するためのコネクション指向型プロトコルです。その信頼性の基盤となるのが、RFC 793で規定されている「スリーウェイハンドシェイク(Three-Way Handshake)」というコネクション確立メカニズムです。このプロセスを通じて、通信を行う両ホストは相互に接続の意思を確認し、データ転送に必要な初期設定を同期します。

設計目標

TCPのスリーウェイハンドシェイクは、以下の主要な目標を達成するために設計されました。

  • 信頼性の高いコネクション確立: 通信を開始する前に、両方のエンドポイントがアクティブであり、通信の準備ができていることを確認します。

  • 初期シーケンス番号 (ISN) の同期: データ転送の順序と信頼性を保証するために不可欠な、両方向の初期シーケンス番号を交換・同期します。これにより、パケットの重複、欠落、順序の誤りを検出・処理する基盤が確立されます。

  • リソースの相互確保: コネクション確立前に、各ホストが必要なバッファや状態情報などのリソースを確保できるようになります。

  • 全二重通信の確立: 一方向だけでなく、両方向で同時にデータ転送が可能な全二重通信路を確立します。

詳細

RFC 793とスリーウェイハンドシェイクの基本

TCPの仕様は、1981年9月に公開されたRFC 793 “Transmission Control Protocol” で詳細に定義されています[1]。そのセクション3.1では、TCPコネクションの確立方法としてスリーウェイハンドシェイクが規定されています。このプロセスは、クライアントとサーバーがそれぞれ初期シーケンス番号 (ISN) を選び、それを相手に通知・確認することで、安全かつ信頼性の高い通信を開始することを目的としています。

TCPヘッダ構造

スリーウェイハンドシェイクを含むTCP通信では、各セグメントにTCPヘッダが付与されます。このヘッダには、コネクションの状態管理に不可欠な情報が含まれています。以下に、主要なフィールドとそのビット長を示します(RFC 793, Section 3.1より)[1]。

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port (16)     |       Destination Port (16)   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number (32)                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number (32)                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data | Rsvd|U|A|P|R|S|F|             Window Size (16)          |
| Offset| (4) |R|C|S|S|Y|I|                                       |
|       |     |G|K|H|T|N|N|                                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum (16)       |         Urgent Pointer (16)   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options (if any) + Padding                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             Data                                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

特に重要なフラグは以下の通りです。

  • SYN (Synchronize): コネクション確立要求、またはシーケンス番号の同期。

  • ACK (Acknowledgment): 確認応答。Acknowledgment Numberフィールドが有効であることを示す。

  • RST (Reset): コネクションのリセット。

  • FIN (Finish): コネクション終了要求。

ハンドシェイクのシーケンス

RFC 793で定義されているスリーウェイハンドシェイクの基本的な流れを以下に示します[1, Sec 3.1]。

sequenceDiagram
    participant Client
    participant Server

    Client ->> Server: SYN (seq=ISN_C)
    Note over Client,Server: クライアントがサーバーへの接続を要求し、自身の初期シーケンス番号 (ISN_C) を通知する。
    Server ->> Client: SYN-ACK (seq=ISN_S, ack=ISN_C+1)
    Note over Client,Server: サーバーはクライアントの要求を確認 (ACK) し、自身の初期シーケンス番号 (ISN_S) を通知する。
    Client ->> Server: ACK (ack=ISN_S+1)
    Note over Client,Server: クライアントはサーバーの応答を確認 (ACK) し、コネクションが確立される。
  1. SYN (Synchronize): クライアントは、サーバーに接続要求を示す SYN フラグを立てたセグメントを送信します。このセグメントには、クライアントが選択した最初のシーケンス番号 (ISN_C) が含まれます。クライアントは SYN-SENT 状態に遷移します。

  2. SYN-ACK (Synchronize-Acknowledge): サーバーはクライアントからの SYN を受信すると、クライアントのISN_Cを ACK (ISN_C+1) で確認し、同時に自身の SYN フラグを立て、サーバーのISN (ISN_S) を含んだセグメントを返信します。サーバーは SYN-RECEIVED 状態に遷移します。

  3. ACK (Acknowledge): クライアントはサーバーからの SYN-ACK を受信すると、サーバーのISN_Sを ACK (ISN_S+1) で確認するセグメントを送信します。このセグメントがサーバーに到達すると、両端でコネクションが ESTABLISHED 状態となり、データの送受信が可能になります。

TCP状態遷移

TCPコネクションは、そのライフサイクルを通じて様々な状態を遷移します。スリーウェイハンドシェイクにおける主要な状態遷移は以下の通りです(RFC 793, Section 3.5より)[1]。

flowchart TD
    CLOSED["CLOSED: コネクションなし"]
    LISTEN["LISTEN: 接続待ち"]
    SYN_SENT["SYN-SENT: SYN送信中"]
    SYN_RECEIVED["SYN-RECEIVED: SYN受信済み"]
    ESTABLISHED["ESTABLISHED: コネクション確立"]

    CLOSED --> |アクティブオープンでSYNを送信| SYN_SENT
    CLOSED --> |パッシブオープンで接続待ち| LISTEN

    LISTEN --> |SYNパケットを受信| SYN_RECEIVED
    SYN_SENT --> |SYN+ACKを受信しACKを送信| ESTABLISHED
    SYN_RECEIVED --> |ACKパケットを受信| ESTABLISHED

    SYN_SENT --> |タイムアウト| CLOSED
    SYN_RECEIVED --> |RSTパケットを受信| LISTEN

相互運用性

TCPのスリーウェイハンドシェイクは、現代のインターネット通信においても広く利用されている基盤技術です。しかし、より高速なウェブ通信や新しい要件に対応するため、TCPとは異なるコネクション確立メカニズムを持つプロトコルも登場しています。

  • TCPを利用するプロトコル (HTTP/1.1, HTTP/2):

    • TCPスリーウェイハンドシェイク(1往復時間: 1-RTT)に加えて、TLSハンドシェイク(通常2-RTT)が必要となり、合計で最低3-RTTの遅延が発生します。

    • HTTP/2はTCPの上でストリームの多重化を行いますが、基盤となるTCPレベルでのHead-of-Line (HOL) Blockingの問題は依然として存在しえます。

  • TCPを利用しないプロトコル (HTTP/3, QUIC):

    • QUIC (Quick UDP Internet Connections) は、UDP上に構築された新しいトランスポートプロトコルであり、2021年5月にRFC 9000として標準化されました[2]。

    • QUICは、独自の暗号化(TLS 1.3)ハンドシェイクとコネクション確立を統合しており、初回接続で1-RTT、以前に接続したサーバーへの再接続では0-RTTでの接続確立を可能にします。

    • TCPとは異なり、QUICは多重化されたストリームが独立しており、一つのストリームのパケットロスが他のストリームに影響を与えるHOL Blockingを回避します。

これらの比較から、TCPの3ウェイハンドシェイクは堅牢ですが、現代の高速化要件に対しては、QUICのようなプロトコルが提供する0-RTT接続やHOL Blocking回避といった最適化が重要視されていることが分かります。

セキュリティ考慮

TCPのスリーウェイハンドシェイクは、長年にわたりインターネットの信頼性を支えてきましたが、いくつかのセキュリティ上の脆弱性も指摘されており、それらに対する対策が講じられてきました。

  • SYN Flood攻撃:

    • 攻撃者は、大量の SYN パケットを送信しますが、最後の ACK パケットを送らずにハンドシェイクを完了させません。これにより、サーバーは多数の SYN-RECEIVED 状態の半開コネクションを維持しようとし、接続キューが溢れ、正当なユーザーからの接続要求を受け付けられなくなります。

    • 対策としては、SYN Cookie(サーバーが状態情報を保持せず、クライアントの応答時に状態を再構築する)や、コネクションキューのサイズを調整するなどの方法があります。

  • シーケンス番号予測攻撃:

    • 初期シーケンス番号 (ISN) が予測可能な場合、攻撃者は正規のクライアントになりすまして偽のパケット(特に RST やデータパケット)を挿入し、コネクションを乗っ取ったり、切断したりする可能性があります。

    • RFC 793はISNを「時間をベースとした32ビットのカウンタ」と定義していますが[1, Sec 3.9]、現代の実装では予測不能な乱数を使用することで、このリスクを軽減しています。

  • RST攻撃:

    • 攻撃者が既存のコネクションに対して偽の RST フラグ付きパケットを送信することで、そのコネクションを強制的に切断することができます。この攻撃は、送信元IPアドレス、送信元ポート、宛先IPアドレス、宛先ポート、そして適切なシーケンス番号を推測できる場合に成功します。
  • 0-RTTの再送リスク:

    • TCPのスリーウェイハンドシェイク自体は0-RTTではありませんが、TCP Fast Open (TFO) (RFC 7413, 2014年12月公開[3]) はTCPにおいて0-RTTのような動作を可能にしますが、これによりリプレイ攻撃のリスクが生じます。QUICの0-RTTも同様のリスクを持ち、プロトコルレベルで対策が施されています。RFC 793の範囲では、このリスクは直接関係しませんが、現代のプロトコルとの比較において言及する価値があります。

実装メモ

TCPコネクションを効果的に管理するためには、スリーウェイハンドシェイク以外の側面にも注意が必要です。

  • Path MTU Discovery (PMTUD):

    • TCPセグメントがIP層でフラグメント化されることを避けるため、パス上の最小MTU(Path MTU)を発見するメカニズムです。これにより、ネットワーク効率が向上し、IPフラグメント化によるパフォーマンス低下やパケットロスを防ぎます。TCPのMaximum Segment Size (MSS) オプションは、このPath MTUを考慮して設定されます。
  • Head-of-Line (HOL) Blockingの可能性:

    • TCPでは、単一のコネクション内でパケットロスが発生した場合、その後のすべてのデータが失われたパケットの再送を待つため、後続のデータ転送がブロックされる可能性があります。これはTCPの順序保証によるもので、HTTP/2のような多重化プロトコルでもTCPを基盤とする限り回避できません。QUICはこの問題を回避しています。
  • キュー制御と輻輳制御:

    • サーバー側では、SYN-RECEIVED 状態のコネクションを保持するためのキュー(backlogキュー)のサイズを適切に管理する必要があります。このキューが溢れると、新たな接続要求が拒否される可能性があります。

    • TCPは、ネットワークの輻輳状況に応じて送信レートを調整する輻輳制御メカニズム(スロースタート、輻輳回避など)を備えており、ネットワーク全体の安定性を保ちます。

  • TIME_WAIT状態:

    • コネクション終了時には、コネクションを閉じた側のソケットが一定期間 (通常2MSL: Maximum Segment Lifetime) TIME_WAIT 状態に留まります。これは、ネットワーク上に残存する可能性のある遅延パケットが新しいコネクションに影響を与えないようにするため、また、最後の ACK が相手に確実に届くことを保証するために重要です。

まとめ

RFC 793で定義されたTCPスリーウェイハンドシェイクは、インターネットの信頼性と安定性の基盤を築き、その後の様々なネットワークアプリケーションの発展を可能にしました。クライアントとサーバーが相互に初期シーケンス番号を同期し、通信開始の合意を形成するこのプロセスは、シンプルながらも非常に堅牢です。

今日に至るまで、SYN Flood攻撃のようなセキュリティ上の課題や、0-RTT接続やHOL Blocking回避といった現代的な要件に対応するための新しいプロトコル(QUICなど)が登場していますが、TCPの基本原則とスリーウェイハンドシェイクの理解は、ネットワークエンジニアにとって依然として不可欠な知識です。現在のネットワーク環境では、TCPを最適化しつつ、QUICのような新しいプロトコルとのバランスを取りながら、より効率的でセキュアな通信環境を構築していくことが、2024年7月26日現在、求められています。

参考文献

[1] IETF RFC Editor. “RFC 793: Transmission Control Protocol”. Published September 1981. URL: https://datatracker.ietf.org/doc/html/rfc793 [2] IETF RFC Editor. “RFC 9000: QUIC: A UDP-Based Multiplexed and Secure Transport”. Published May 2021. URL: https://datatracker.ietf.org/doc/html/rfc9000 [3] IETF RFC Editor. “RFC 7413: TCP Fast Open”. Published December 2014. URL: https://datatracker.ietf.org/doc/html/rfc7413

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました