5. 接続 (Connections)
5. 接続
QUIC接続は、クライアントとサーバー間の共有状態です。
各接続は、ハンドシェイクフェーズから始まり、この間に2つのエンドポイントは暗号ハンドシェイクプロトコル [QUIC-TLS] を使用して共有鍵を確立し、アプリケーションプロトコルをネゴシエートします。ハンドシェイク(セクション7)は、両方のエンドポイントが通信する意思があることを確認し(セクション8.1)、接続のパラメータを確立します(セクション7.4)。
アプリケーションプロトコルは、ハンドシェイクフェーズ中に接続を使用できますが、いくつかの制限があります。0-RTTは、クライアントがサーバーの応答を受信する前にアプリケーションデータを送信することを許可します。ただし、0-RTTはリプレイ攻撃に対する保護を提供しません。[QUIC-TLS]のセクション9.2を参照してください。サーバーも、クライアントのアイデンティティとアクティビティを確認できる最終的な暗号ハンドシェイクメッセージを受信する前に、クライアントにアプリケーションデータを送信できます。これらの機能により、アプリケーションプロトコルは、一部のセキュリティ保証と引き換えにレイテンシを削減するオプションを提供できます。
接続ID(セクション5.1)の使用により、エンドポイントの直接的な選択として、またはミドルボックスの変更によって強制された場合に、接続が新しいネットワークパスに移行できます。セクション9では、移行に関連するセキュリティとプライバシーの問題の緩和策について説明します。
もはや必要でないか望まれない接続については、クライアントとサーバーは、セクション10で説明されているように、接続を終了するいくつかの方法を持っています。
5.1 [接続ID (Connection ID)
各接続は、接続識別子または接続IDのセットを持ち、それぞれが接続を識別できます。接続IDはエンドポイントによって独立して選択されます。各エンドポイントは、ピアが使用する接続IDを選択します。
接続IDの主な機能は、下位プロトコル層(UDP、IP)のアドレッシングの変更がQUIC接続のパケットを間違ったエンドポイントに配信させないことを保証することです。各エンドポイントは、実装固有(おそらく展開固有)の方法を使用して接続IDを選択し、その接続IDを持つパケットがエンドポイントにルーティングされ、受信時にエンドポイントによって識別されることを可能にします。
複数の接続IDを使用することで、エンドポイントは、エンドポイントと協力していない観察者によって同じ接続に属すると識別できないパケットを送信できます。セクション9.5を参照してください。
接続IDには、外部の観察者(つまり、発行者と協力していない観察者)が同じ接続の他の接続IDと関連付けるために使用できる情報を含めてはなりません。簡単な例として、これは同じ接続IDが同じ接続で複数回発行されてはならないことを意味します。
長いヘッダーを持つパケットには、ソース接続ID (Source Connection ID) とデスティネーション接続ID (Destination Connection ID) フィールドが含まれます。これらのフィールドは、新しい接続の接続IDを設定するために使用されます。詳細については、セクション7.2を参照してください。
短いヘッダーを持つパケット(セクション17.3)には、デスティネーション接続IDのみが含まれ、明示的な長さは省略されます。デスティネーション接続IDフィールドの長さは、エンドポイントに既知であることが期待されます。接続IDベースのルーティングを使用するロードバランサーを使用するエンドポイントは、接続IDの固定長についてロードバランサーと合意するか、エンコーディングスキームについて合意できます。固定部分は明示的な長さをエンコードでき、これにより接続ID全体の長さが変化しても、ロードバランサーによって使用されることができます。
バージョンネゴシエーション(セクション17.2.1)パケットは、クライアントが選択した接続IDをエコーバックします。これは、パケットがクライアントに正しくルーティングされることを保証し、パケットがクライアントが送信したパケットへの応答であることを証明するためです。
接続IDが正しいエンドポイントへのルーティングに必要ない場合、ゼロ長の接続IDを使用できます。ただし、ゼロ長の接続IDを使用する場合、同じローカルIPアドレスとポートで接続を多重化すると、ピア接続の移行、NATの再バインド、クライアントポートの再利用の存在下で失敗につながります。エンドポイントは、これらのプロトコル機能が使用されていないことを確信していない限り、ゼロ長の接続IDを持つ複数の並行接続に同じIPアドレスとポートを使用してはなりません。
エンドポイントが非ゼロ長の接続IDを使用する場合、ピアがエンドポイントに送信するパケットに使用するのに十分な接続IDをピアが持っていることを確認する必要があります。これらの接続IDは、NEW_CONNECTION_IDフレーム(セクション19.15)を使用してエンドポイントによって提供されます。
5.1.1 接続IDの発行 (Issuing Connection IDs)
各接続IDには、NEW_CONNECTION_IDまたはRETIRE_CONNECTION_IDフレームが同じ値を参照するタイミングを検出するのに役立つ関連するシーケンス番号があります。エンドポイントが発行する初期接続IDは、ハンドシェイク中に長いパケットヘッダーのソース接続IDフィールド(セクション17.2)で送信されます。初期接続IDのシーケンス番号は0です。preferred_addressトランスポートパラメータが送信される場合、提供される接続IDのシーケンス番号は1です。
追加の接続IDは、NEW_CONNECTION_IDフレーム(セクション19.15)を使用してピアに伝達されます。新しく発行される各接続IDのシーケンス番号は1ずつ増加しなければなりません。クライアントが最初に送信するデスティネーション接続IDフィールドに選択する接続ID、およびRetryパケットが提供する接続IDには、シーケンス番号は割り当てられません。
エンドポイントが接続IDを発行する場合、接続中またはピアがRETIRE_CONNECTION_IDフレーム(セクション19.16)によって接続IDを無効にするまで、この接続IDを運ぶパケットを受け入れなければなりません。発行され、廃止されていない接続IDはアクティブと見なされます。アクティブな接続IDはいつでも、どのパケットタイプでも現在の接続に対して有効です。これには、サーバーがpreferred_addressトランスポートパラメータを介して発行する接続IDが含まれます。
エンドポイントは、ピアが十分な数の利用可能で未使用の接続IDを持つことを保証すべきです。エンドポイントは、active_connection_id_limitトランスポートパラメータを使用して、維持する意思のあるアクティブな接続IDの数を通知します。エンドポイントは、ピアの制限を超える接続IDを提供してはなりません。NEW_CONNECTION_IDフレームが超過分の一部を廃止することも要求する場合、エンドポイントは、Retire Prior Toフィールドに十分に大きな値を含めることにより、ピアの制限を一時的に超える接続IDを送信できます。
NEW_CONNECTION_IDフレームは、Retire Prior Toフィールドの値に基づいて、エンドポイントがいくつかのアクティブな接続IDを追加し、他のアクティブな接続IDを廃止する原因となる可能性があります。NEW_CONNECTION_IDフレームを処理し、アクティブな接続IDを追加および廃止した後、アクティブな接続IDの数がactive_connection_id_limitトランスポートパラメータで通知された値を超える場合、エンドポイントはCONNECTION_ID_LIMIT_ERRORタイプのエラーで接続を閉じなければなりません。
ピアが接続IDを廃止する場合、エンドポイントは新しい接続IDを提供すべきです。エンドポイントがピアのactive_connection_id_limitよりも少ない接続IDを提供している場合、以前に未使用の接続IDを持つパケットを受信したときに新しい接続IDを提供できます。エンドポイントは、接続IDが枯渇するリスクを回避するために、接続ごとに発行する接続IDの総数を制限できます。セクション10.3.2を参照してください。エンドポイントは、発行された接続IDと同じ数のパスを介してピアがエンドポイントと対話できる可能性があるため、パス検証状態などの各パス状態の量を減らすために接続IDの発行を制限することもできます。
移行を開始し、非ゼロ長の接続IDを必要とするエンドポイントは、ピアが移行時に新しい接続IDを使用できるように、ピアが利用できる接続IDのプールを確保すべきです。プールが枯渇すると、ピアは応答できなくなるためです。
ハンドシェイク中にゼロ長の接続IDを選択したエンドポイントは、新しい接続IDを発行できません。このようなエンドポイントに任意のネットワークパスを介して送信されるすべてのパケットで、ゼロ長のデスティネーション接続IDフィールドが使用されます。
5.1.2 接続IDの消費と廃止 (Consuming and Retiring Connection IDs)
エンドポイントは、接続中いつでもピアに使用する接続IDを別の利用可能な接続IDに変更できます。エンドポイントは、移行するピアに応答して接続IDを消費します。詳細については、セクション9.5を参照してください。
エンドポイントは、ピアから受信した接続IDのセットを維持し、パケットを送信するときにそのいずれかを使用できます。エンドポイントが使用中から接続IDを削除したい場合、ピアにRETIRE_CONNECTION_IDフレームを送信します。RETIRE_CONNECTION_IDフレームを送信することは、その接続IDがもはや使用されないことを示し、ピアにNEW_CONNECTION_IDフレームで置き換えるよう要求します。
セクション9.5で説明されているように、エンドポイントは、単一のローカルアドレスから単一のデスティネーションアドレスに送信されるパケットに接続IDの使用を制限します。エンドポイントが接続IDが使用されていたローカルまたはデスティネーションアドレスをもはやアクティブに使用していない場合、接続IDを廃止すべきです。
エンドポイントは、以前に発行した接続IDの受け入れを停止する必要がある場合があります。このようなエンドポイントは、Retire Prior Toフィールドを増加させたNEW_CONNECTION_IDフレームを送信することにより、ピアに接続IDを廃止させることができます。エンドポイントは、ピアによって廃止されるまで、以前に発行した接続IDを受け入れ続けるべきです。エンドポイントが指示された接続IDを処理できなくなった場合、接続を閉じることができます。
Retire Prior Toフィールドの増加を受信した後、ピアは対応する接続IDの使用を停止し、新しく提供された接続IDをアクティブな接続IDセットに追加する前に、RETIRE_CONNECTION_IDフレームを使用してそれらを廃止しなければなりません。この順序により、エンドポイントは、ピアが利用可能な接続IDを持たない可能性や、active_connection_id_limitトランスポートパラメータでピアが設定した制限を超える可能性なく、すべてのアクティブな接続IDを置き換えることができます。セクション18.2を参照してください。要求されたときに接続IDの使用を停止しないと、発行エンドポイントがアクティブな接続で接続IDを引き続き使用できない可能性があるため、接続の失敗につながる可能性があります。
エンドポイントは、ローカルで廃止したがRETIRE_CONNECTION_IDフレームがまだ確認されていない接続IDの数を制限すべきです。エンドポイントは、active_connection_id_limitトランスポートパラメータ値の少なくとも2倍のRETIRE_CONNECTION_IDフレーム数の送信と追跡を許可すべきです。エンドポイントは、接続IDを廃止せずに接続IDを忘れてはなりませんが、この制限を超える廃止を必要とする接続IDをCONNECTION_ID_LIMIT_ERRORタイプの接続エラーとして扱うことを選択できます。
エンドポイントは、以前のすべてのRetire Prior To値が示す接続IDを廃止するRETIRE_CONNECTION_IDフレームを受信する前に、Retire Prior Toフィールドの更新を発行すべきではありません。
5.2 [パケットを接続に照合する (Matching Packets to Connections)
受信パケットは、受信時に分類されます。パケットは既存の接続に関連付けられるか、サーバーの場合は新しい接続を作成する可能性があります。
エンドポイントは、パケットを既存の接続に関連付けようとします。パケットが既存の接続に対応する非ゼロ長のデスティネーション接続IDを持つ場合、QUICはそれに応じてパケットを処理します。複数の接続IDが接続に関連付けられる可能性があることに注意してください。セクション5.1を参照してください。
デスティネーション接続IDがゼロ長で、パケットのアドレッシング情報がエンドポイントがゼロ長の接続IDを持つ接続を識別するために使用するアドレッシング情報と一致する場合、QUICはそのパケットをその接続の一部として処理します。エンドポイントは、デスティネーションIPとポートのみを使用するか、ソースとデスティネーションの両方のアドレスを使用して識別できますが、これによりセクション5.1で説明されているように接続が脆弱になります。
エンドポイントは、既存の接続に帰属できないパケットに対してステートレスリセット(セクション10.3)を送信できます。ステートレスリセットにより、ピアは接続がいつ使用不可能になったかをより迅速に識別できます。
既存の接続と一致するパケットは、その接続の状態と一致しない場合は破棄されます。たとえば、パケットが接続と異なるプロトコルバージョンを示している場合、または期待されるキーが利用可能になった後でパケット保護の削除が成功しない場合、パケットは破棄されます。
強力な完全性保護を欠く無効なパケット(たとえば、Initial、Retry、またはVersion Negotiation)は破棄できます。エンドポイントがエラーを発見する前にこれらのパケットの内容を処理する際に接続エラーを生成するか、その処理中に行われた変更を完全に元に戻す場合、接続エラーを生成しなければなりません。
5.2.1 クライアントパケット処理 (Client Packet Handling)
クライアントに送信される有効なパケットには、常にクライアントが選択した値と一致するデスティネーション接続IDが含まれます。ゼロ長の接続IDを受信することを選択したクライアントは、ローカルアドレスとポートを使用して接続を識別できます。デスティネーション接続ID、または(この値がゼロ長の場合)ローカルIPアドレスとポートに基づいて既存の接続と一致しないパケットは破棄されます。
パケットの再順序付けや損失により、クライアントはまだ計算していないキーで暗号化された接続パケットを受信する可能性があります。クライアントはこれらのパケットを破棄するか、後のパケットがキーの計算を可能にすることを期待してバッファリングできます。
クライアントが最初に選択したバージョンとは異なるバージョンを使用するパケットを受信した場合、そのパケットを破棄しなければなりません。
5.2.2 サーバーパケット処理 (Server Packet Handling)
サーバーがサポートされていないバージョンを示すパケットを受信し、パケットがサポートされているバージョンの新しい接続を開始するのに十分な大きさである場合、サーバーはセクション6.1で説明されているようにバージョンネゴシエーションパケットを送信すべきです。サーバーは、バージョンネゴシエーションパケットで応答するパケットの数を制限できます。サーバーは、サポートされていないバージョンを指定する小さいパケットを破棄しなければなりません。
サポートされていないバージョンの最初のパケットは、バージョン固有のフィールドに異なるセマンティクスとエンコーディングを使用する可能性があります。特に、異なるバージョンは異なるパケット保護キーを使用する可能性があります。特定のバージョンをサポートしていないサーバーは、パケットのペイロードを復号化したり、結果を正しく解釈したりできる可能性は低いです。サーバーは、データグラムが十分に大きい場合、バージョンネゴシエーションパケットで応答すべきです。
サポートされているバージョンを持つパケット、またはバージョンフィールドを持たないパケットは、接続IDを使用して、またはゼロ長の接続IDを持つパケットの場合はローカルアドレスとポートを使用して接続に照合されます。これらのパケットは選択された接続を使用して処理されます。それ以外の場合、サーバーは以下のように続行します。
パケットが完全に適合するInitialパケットである場合、サーバーはハンドシェイク(セクション7)を続行します。これにより、サーバーはクライアントが選択したバージョンにコミットします。
サーバーが新しい接続の受け入れを拒否する場合、CONNECTION_REFUSEDのエラーコードを含むCONNECTION_CLOSEフレームを含むInitialパケットを送信すべきです。
パケットが0-RTTパケットである場合、サーバーは遅延して到着するInitialパケットを期待して、これらのパケットの限られた数をバッファリングできます。クライアントはサーバーの応答を受信する前にHandshakeパケットを送信できないため、サーバーはそのようなパケットを無視すべきです。
サーバーは、他のすべての場合に受信パケットを破棄しなければなりません。
5.2.3 シンプルなロードバランサーの考慮事項 (Considerations for Simple Load Balancers)
サーバーの展開は、ソースとデスティネーションのIPアドレスとポートのみを使用してサーバー間でロードバランシングできます。クライアントのIPアドレスまたはポートの変更により、パケットが間違ったサーバーに転送される可能性があります。クライアントアドレスが変更された場合、このようなサーバーの展開は、接続の連続性を維持するために次のいずれかの方法を使用できます。
-
サーバーは、帯域外メカニズムを使用して、接続IDに基づいてパケットを正しいサーバーに転送できます。
-
サーバーが専用のサーバーIPアドレスまたはポート(クライアントが最初に接続したアドレスまたはポートとは異なる)を使用できる場合、preferred_addressトランスポートパラメータを使用して、クライアントに接続をその専用アドレスに移動するよう要求できます。クライアントは優先アドレスを使用しないことを選択できることに注意してください。
クライアントアドレスが変更されたときに接続の連続性を維持するソリューションを実装していない展開のサーバーは、disable_active_migrationトランスポートパラメータを使用して移行がサポートされていないことを示すべきです。disable_active_migrationトランスポートパラメータは、preferred_addressトランスポートパラメータに対処した後のクライアントの接続移行を禁止しません。
このようなシンプルな形式のロードバランシングを使用するサーバーの展開は、ステートレスリセットオラクルの作成を避けなければなりません。セクション21.11を参照してください。
5.3 [接続の操作 (Operations on Connections)
このドキュメントはQUICのAPIを定義していません。代わりに、アプリケーションプロトコルが依存できるQUIC接続の関数セットを定義します。アプリケーションプロトコルは、QUICの実装が本セクションで説明されている操作を含むインターフェースを提供すると仮定できます。特定のアプリケーションプロトコル用に設計された実装は、そのプロトコルが使用する操作のみを提供する場合があります。
クライアントロールを実装する場合、アプリケーションプロトコルは次のことができます:
- 接続を開く。これによりセクション7で説明されている交換が開始されます。
- Early Dataを有効にする(利用可能な場合)。
- Early Dataがサーバーによって受け入れられたか拒否されたかを通知される。
サーバーロールを実装する場合、アプリケーションプロトコルは次のことができます:
- 着信接続をリッスンする。これによりセクション7で説明されている交換の準備が行われます。
- Early Dataをサポートする場合、クライアントに送信されるTLS再開チケットにアプリケーション制御データを埋め込みます。
- Early Dataをサポートする場合、クライアントの再開チケットからアプリケーション制御データを取得し、その情報に基づいてEarly Dataを受け入れるか拒否します。
どちらのロールでも、アプリケーションプロトコルは次のことができます:
- 各タイプの許可されるストリームの初期数の最小値を構成する。これはトランスポートパラメータで伝達されます(セクション7.4)。
- ストリームと接続のフロー制御制限を設定することにより、受信バッファのリソース割り当てを制御する。
- ハンドシェイクが正常に完了したか、まだ進行中かを識別する。
- PINGフレームを生成する(セクション19.2)か、アイドルタイムアウトが期限切れになる前に追加のフレームを送信するようトランスポートに要求することにより、接続がサイレントに閉じるのを防ぐ(セクション10.1)。
- 即座に接続を閉じる(セクション10.2)。
前の章: 4. フロー制御 (Flow Control)
次の章: 6. バージョンネゴシエーション (Version Negotiation)