RFC3489を訳してみる

STUNについて把握する必要が出てきたので、まずは古い実装のrfc3489を読んでみる。 日本語訳の正確さは保証しない、というかツッコミどころがあるはずなので、 気付いた方はコメント頂けると幸いです。

STUN - UDPのNAT超えのためのシンプルなプロトコル

  1. 適用声明  このプロトコルはNATと関連した問題の万能薬ではない。 内向きのTCPコネクションでのNAT超えは可能にはならない。 UDPのインバウンドパケットのNAT超えを可能にするが、現存するNATの種類のうちの一部について可能にするものである。 とりわけSTUNでは、大企業で一般的に用いられている対称NAT(定義は後述する)を超えることはできない。 STUNの発見手順は、NATでのUDPの取り扱いについての家庭に基づいている。 こういった過程は、新たなNATデバイスが採用されると無効になると示すことができるかもしれない。 STUNは、同じNATの後ろにあるピアと通信するためにアドレスを取得した場合には動作しない。 STUNはSTUNサーバが一般的な共有アドレスの範囲にない場合は動作しない。 STUNサーバの制約についてのより完全な議論は、14章に示す。

  2. 序論 ネットワークアドレス変換(NAT)は、多くの利点をもたらす一方で、多くの欠点がつきものである。 これらの欠点の内最も問題となるのは、既存のIPアプリケーションの多くを壊してしまい、新たなアプリケーションの設計を困難にするという事実である。 ガイドラインは既に公開されているが[8]、これらのガイドラインに従って、単純に多くのプロトコルを構成することはできない。 このようなプロトコルの例は、マルチメディアコミュニケーションやファイル共有やゲームといった、殆どのp2pプロトコルを含む。

この問題を防止するため、アプリケーションレイヤのゲートウェイ(ALGs)がNATに組み込まれている。 ALGは特定のプロトコルのNAT超えのためのアプリケーション層の機能を実行する。 概ね、この機能は、メッセージの送信者が挿入したメッセージよりも、変換後のアドレスを含むように、アプリケーション層のメッセージの書き換えを行う挙動を含む。 AGLには、拡張性や信頼性, 新たなアプリケーション導入のスピードを含む深刻な制約がある。 この問題を解決するため、Middlebox Communicationsプロトコル(MIDCOM)が開発中である。[9] MIDCOMは、終端のクライアントや(SIPプロキシのような)幾つかの目的のネットワークサーバのようなアプリケーションの実体が、NAT割当を取得しpinholeを空けたり閉じたりするためにNATを操作することを許可する。 この手法では、NATとアプリケーションは、ALGをNATに組み込む必要性がなくなるので、以前のように分離することが可能になる。 そして、現在の構成に由来する制約を解決することができる。

不幸なことに、MIDCOMは、アプリケーションの構成に加えて、既存のNATやファイアーウォールを更新する必要がある。 それらのNATやFirewallの更新には長期間かかるだろう。可能性としては数年単位になる。 これは、部分的には、NATとFirewallの採用者がアプリケーションの採用者と異なるのが原因である。 結果として、多くのケースで、これらのデバイスの更新の動機は少ない。 例えば、NATでのアクセスを提供している空港のインターネットラウンジを考えると、 NATのネットワークに接続しているユーザがp2pのアクセスをしたいと考えてるかもしれない。 しかし、NATがサポートしていないので、それはできない。 ラウンジの管理者は、サービスの提供者とは異なるため、 ALGやMIDCOMをサポートするNATに入れ替えるモチベーションは低い。

もう一つの問題として、MIDCOMプロトコルでは、middleboxをコントロールするエージェントはそれらのmiddleboxの正体を知っており、コントロールを許可するために関係を持つ必要があることがあげられる。 多くの設定において、これは不可能だ。 例えば、多くのケーブルアクセスプロバイダーは、それらのアクセス網全体の前でNATを利用している。 住居用のNATの他に、エンドユーザによって購入され設定されたNATがあるかもしれない。 エンドユーザはケーブルアクセス網のNATのコントロールができないかもしれない。 そして、その存在にすら気付かないかもしれない。

(RFC3027で述べられているような)オンラインゲームやVoice over IP用のプロトコルのような、既存の私有プロトコルの多くは、 それらのNATの設定を変更しないでNATを超えて実行するためのトリックを実装してきている。 このドキュメントはそれらのアイデアのいくつかを採用し、多くのアプリケーションの要求を満たす横断的に利用できるプロトコルとして体系化する試みである。

ここで述べるプロトコルは、シンプルなUDPのNAT超えであり、NATの後ろにあるものに、まずNATの存在とその種類を検出させ、 NATに割り当てられたアドレスを学習させることを可能にする。 STUNはNATの変更を必要とせず、アプリケーションとインターネットの間に任意の数のNATがタンデム接続されている環境においても動作する。

3 専門用語 このドキュメントでは、「必須」「必須ではない」「要求される」「すべきである」「すべきではない」「するのが当然である」「しないほうがよい」「推奨される」「してもよい」「任意」というキーワードをRFC2119で記載されているような意味で用いることで、 STUN実装の要件の要求レベルについて述べる。

  1. 定義 STUNクライアント: STUNクライアントとは、STUNのリクエストを生成する実装のことである。STUNクライアントは、ユーザのPCのような末端のシステムで実行することができる。もしくは、電話会議サーバのようなネットワーク上の一要素の上で実行することができる。

STUNサーバ: STUNサーバとは、STUNリクエストを受け取りSTUNレスポンスを返す実装のことである。STUNサーバは一般的にはインターネット上に公開される。

  1. NATのバリエーション

読み手はNATに詳しい物と仮定する。UDPでのNATの扱いは、実装によって変化することが観測されている。 以下の4つの実装があることが明らかになっている。

Full Cone: フルコンNATとは、同一の内部IPアドレスとポートからのリクエストは全て同じ外部IPアドレスとポートに割り当てるNATである。 更に、全ての外部ホストは、割り当てられた外部IPアドレスに対してパケットを送ることで、内部ホストに対してパケットを送ることができる。

Restricted Cone: 制限コーンNATとは、同一の内部IPアドレスとポートからの全ての通信が、同一の外側IPアドレスとポートに割り当てられるNATである。フルコーンNATとは異なり、内部ホストから通信を行った対称の外部ホストのみ内部ホストへパケットを送ることができるという点である。

Port Restricted Cone: ポート制限コーンNATは制限コーンNATに似ているが、ポート番号の制約が追加されている。 とりわけ、外部ホストは、内部ホストからパケットを受信したIPアドレス及びポート番号の組み合わせからのみ、 内部ホストへパケットを送ることができる。

Symmetric: シンメトリックNATは、同一のIPアドレスとポート番号から特定の宛先IPアドレスとポートに対して送信された全てのパケットが、 同一の外側IPアドレスとポートの組にマッピングされるNATである。 同一のホストが同一のIPアドレスとポート番号から送信したパケットであっても、異なる宛先に対して送信したパケットは、 異なる外側IPアドレスとポート番号の組にマッピングされる。 更に、パケットを受信した外側ホストのみ、内部ホストに対してパケットを送り返すことができる。

NATの種類を特定することは多くのケースで重要である。 アプリケーションが何を行いたいかに依存して、特定のふるまいをすることを考える必要があるかもしれない。

  1. 動作の概要

この章では描写のみを行う。規範的なふるまいについては8章と9章で記述する。

                        /-----\
                      // STUN  \\
                     |   Server  |
                      \\       //
                        \-----/


                   +--------------+             Public Internet
   ................|     NAT 2    |.......................
                   +--------------+


                   +--------------+             Private NET 2
   ................|     NAT 1    |.......................
                   +--------------+

                        /-----\
                      // STUN  \\
                     |   Client  |
                      \\       //               Private NET 1
                        \-----/

                 Figure 1: STUN Configuration

典型的なSTUNの配置を図1に示す。STUNクライアントはプライベートネットワーク1に接続されている。 このネットワークはプライベートネットワーク2にNAT1を介して接続している。 プライベートネットワーク2はインターネットにNAT2を介して接続している。 STUNサーバはインターネット上に配置されている。

STUNはシンプルなクライアント-サーバモデルのプロトコルである。 クライアントはサーバにリクエストを送信し、サーバは応答を返す。 2種類のリクエストがあり、UDPで送信されるBinding Requestと、TLS over TCPで送信されるShared Secret Requestがある。 Shared Secret Requestは、サーバに一時ユーザネームとパスワードを要求する。 このユーザネームとパスワードは、その後のBinding RequestとBinding Responseで、 認証とメッセージの完全性を目的として利用される。

Binding RequestはNATによって割り当てられたbindingを特定するのに利用される。 クライアントは、Binding RequestをUDPでサーバへ送信する。 サーバはリクエストのソースIPアドレスとポートを検証し、 レスポンスにコピーしてクライアントへ返送する。 リクエストにはいくつかのパラメータがあり、 レスポンスをどこか別のところへ送信するよう要求することや、 サーバが別のアドレスやポート番号から返送するよう要求することを可能にする。 メッセージの完全性や認証を提供するための項目もある。

こつは、STUNを使ってNATの存在を発見することや、NATが割り当てたbindingを学習し利用することである。

典型的なSTUNクライアントは、アプリケーションに組み込まれており、 データを取得するのに利用できるpublic IPアドレスやポート番号を取得する。 例えば、RTPのトラフィックを受信するために、IPアドレスやポート番号を取得するのに必要かもしれない。 アプリケーション起動時に、アプリケーション内のSTUNクライアントは、STUN Shared Secret Requestを STUNサーバへ送信する。 STUNサーバは、DNSサーバを利用して発見することができ、 一般的には、クライアントはSTUNサーバを利用するためにドメイン名を利用するように設定されていると想定される。 大抵は、各サービスプロバイダーのドメインで運用することになるだろう (このようなプロバイダーは顧客に対して、自分たちのアプリケーションでのNAT超えを可能にするために STUNサーバを運用するインセンティブがある。) もちろん、クライアントは他の手段を用いて、STUNサーバのアドレスやドメイン名を特定してもよい。 STUNサーバもエンドシステムに組み込むことが可能である。

STUNのBinding Requestは、NATの存在を検出し、NATによって割り当てられたpublic IPアドレスとポート番号を検出するために用いられる。 Binding RequestはSTUNサーバに対し、UDPで送信される。 Binding RequestがSTUNサーバに届いたら、そのリクエストはSTUNクライアントとSTUNサーバの間に存在する、 一つかそれ以上のNATを超えてきたかもしれない。 結果として、サーバが受信するリクエストのソースアドレスは、サーバに最も近いNATが割り当てたIPアドレスとポート番号である。 STUNサーバはそのソースIPアドレスとポート番号をSTUN Binding Responseにコピーし、 ソースIPアドレスとポート番号に対して送り返す。 上述した全てのNATの種類において、このレスポンスはSTUNクライアントまで到着するだろう。

STUNクライアントがSTUN Binding Responseを受信すると、クライアントは受信したIPアドレスとポート番号を、 リクエストを送信したときのローカルIPアドレスとポート番号との比較を行う。 それらが一致しなければ、STUNクライアントは一つ以上のNATの後ろにいることになる。 フルコンNATではこのような場合、STUNレスポンスのボディに記載されたIPアドレスとポート番号はパブリックであり、 インターネット上の全てのホストがこれを利用して、STUNリクエストを送信したアプリケーションに対して パケットを送ることができる。 アプリケーションは、STUNリクエストを送信したIPアドレスとポート番号でパケットを待ち受けるだけでよい。 STUNによって学習されたpublicアドレスとポート番号に対して、 インターネット上のホストから送信された全てのパケットは、アプリケーションに受信されることになる。

もちろん、クライアントは、フルコンNATの背後にはいないかもしれない。 実際、どのような種類のNATの背後にいるのかは、まだ知ることができない。 それを決定するために、クライアントは追加のSTUN Binding Requestを利用する。 正確な手順は柔軟であるが、一般的には以下のように動作するだろう。 クライアントは、同一のIPアドレスとポート番号から、 異なるIPアドレス向けに二つ目のSTUN Binding Requestを送信するだろう。 STUNレスポンスに含まれるIPアドレスとポート番号が、最初のSTUNレスポンスに含まれたものと異なるとき、 クライアントは、自分がこのとき、シンメトリックNATの背後に居ることを理解する。 フルコンNATの背後に居ると決定するために、クライアントはSTUN Binding Requestにフラグを立てて送信する。 そのフラグは、STUNサーバに、STUNリクエストを受信したのとは別のIPアドレスとポートからSTUNレスポンスを返送するよう要求するものである。 言い換えると、もしクライアントがBinding Requestを、送信元IPアドレスX, 送信元ポート番号Yから宛先IPアドレスA, ポート番号Bに対して送信したとすると、 STUNサーバはBinding Responseを送信元IPアドレスC, 送信元ポート番号Dを利用して宛先IPアドレスX, 宛先ポート番号Yに対して送信する。 クライアントがこのレスポンスを受信すれば、このクライアントはフルコンNATの背後にいることがわかる。

STUNクライアントはサーバに、リクエストを受信したのと同じIPアドレスと異なるポート番号からBinding Responseを送信することを要求できる。 これにより、クライアントは、自分がポート制限コーンNATの後ろにいるのか、単に制限コーンNATの後ろにいるのかを判別することができる。

注意しておくべき事は、図1の構成だけが許容される構成ではないということだ。 STUNサーバは、別のクライアントの内部も含めて、どこにでも配置できる。 STUNサーバに対する唯一の要求事項は、クライアントから通信可能であるということだけだ。 そして、もしクライアントがroutableなpublic IPアドレスを取得しようとすると、 サーバはインターネットに接続されていることになる。

  1. メッセージ概要

STUNメッセージは、TLV(type-length-value)形式のビッグエンディアンのバイナリである。 全てのSTUNメッセージは先頭にSTUNヘッダがあり、STUNペイロードが続く。 ペイロードは一連のSTUN attributeであり、構成はメッセージタイプに依存する。 STUNヘッダはSTUNのメッセージタイプ、トランザクションIDと長さを含む。 メッセージタイプはBinding Request, Binding Response, Binding Error Response, Shared Secret Request, Shared Secret Response, Shared Secret Error Responseが設定できる。 トランザクションIDは、リクエストとレスポンスを関連づけるのに用いられる。 lengthはSTUNペイロードのトータルの長さを示す物で、ヘッダは含まない。 これはSTUNをTCPで動作させるのに利用できる。 Shared Secret Requestsは常にTCPを利用して送信される。(実際には、TLS over TCPを利用する。)

いくつかのSTUN attributeが定義されている。 まずはMAPPED-ADDRESS attributeで、IPアドレスとポートである。 これは常にBinding Responseに含まれ、STUNサーバがBinding Requestで観測したソースIPアドレスとポート番号を示す。 RESPONSE-ADDRESS attributeというものもあり、Binding Requestに含めることができる。 これはBinding Responseの宛先となるIPアドレスとポートを示す。 これはオプショナルであり、設定されていない場合、Binding ResponseはBinding Requestの送信元IPとポート番号に送信される。

三つ目のattributeはCHANGE-REQUEST attributeで、これはレスポンスを送信するIPアドレスとポート番号を操作するための2つのフラグを含む。 これらのフラグは”Change IP”と”Change port”フラグと呼ばれる。 CHANGE-REQUEST attributeはBinding Requestにのみ設定することを許される。 Change IPとChange portフラグは、クライアントが制限コーンNATの後ろにいるのか、ポート制限コーンNATの後ろに居るのかを 判断するのに利用できる。 これらはサーバに対し、Binding Responseを異なるソースIPアドレスとポート番号から送信するように指示する。 CHANGE-REQUEST attributeはBinding Requestのオプショナルフィールドである。

4つめのattributeは、CHANGED-ADDRESS attributeである。 これはBinding Responseに含まれる。 これはクライアントに、クライアントが”Change IP”や”Change port”を要求した場合に利用する事のできるソースIPアドレスとポート番号を知らせるものである。

5つめのattributeは、SOURCE-ADDRESS attributeである。 Binding Responseにのみ含まれる。 これはレスポンスの送信元IPアドレスとポート番号を示す。 これはNATの設定を二度確認するのに役立つ。

6つめのattributeはUSERNAME attributeである。 Shared Secret Responseに含まれ、一時的なユーザ名やパスワードを通知する。(パスワードはPASSWORD attributeに含まれ、暗号化されている) USERNAMEはBinding Requestにも含まれる。 shared secretのインデックスとして提供され、Binding Requestの完全性を保つために利用される。 7つめのattributeはPASSWORDで、Shared Secret Responseにのみ含まれる。 8つめのattributeはMESSAGE-INTEGRITYで、Binding RequestやBinding Resoonseの完全性を確認するのに利用される。

9つめのattributeは、ERROR-CODEである。 これはBinding Error ResponseとShared Secret Error Responseに含まれる。 これは発生したエラーを示すのに利用される。 10個めのattirbuteは、UNKNOWN-ATTRIBUTEで、Binding Error ResponseやShared Secret Error Responseに含まれる。 リクエストの中の必須のattributeが不明であったことを示す。 11個めのattributeは、REFLECTED-FROM attributeで、Binding Responseに含まれる。 これはBinding RequestのIPアドレスと送信者を示し、 dos攻撃を予防する目的でのトレーサビリティを確保するために利用される。

  1. Serverの挙動

サーバのふるまいは、リクエストがBinding RequestかShared Secret Requestかに依存する

8.1 Binding Requests

Stunサーバは4つのアドレスとポートの組み合わせにおいて、 Binding Requestを受信する準備をしなければならない。 その組み合わせを(A1, P1), (A2, P1), (A1, P2), (A2, P2)とする。 (A1, P1)はプライマリのアドレスとポートの組み合わせで、以下のclientの発見手順で発見できなければならない。 通常、P1は3478を利用する。3478はSTUNの標準ポートである。 A2, P2は任意に設定できる。A2とP2はサーバのCHANGED-ADDRESS attributeで公告される。

STUNサーバはBinding RequestのMESSAGE-INTEGRITY attributeを確認することを推奨する。 含まれておらず、サーバがメッセージの完全性を確認したい場合は、 ERROR-CODEに401を設定したBinding Error Responseを送信する。 MESSAGE-INTEGRITY attributeが存在する場合、 サーバは11.2.8節で詳述するが、リクエスト上でHMACを実行する。 STUN Shared Secret Requestが利用された場合、このキーは、過去に用いられたUSERNAME attributeと一意に一致しなければならない。 USERNEME attributeが設定されていない場合、サーバはBinding Error Responseを返さなければならない。 このBinding Error Responseにはコード432を含まなければならない。 USERNAMEが設定されていて、サーバがそのUSERNAMEを記憶していない場合、 サーバはBinding Error Responseを返さなければならない。 そのError Responseにはコード430を含まなければならない。 サーバがshared secretを知っていて、HMACがリクエストと一致しない場合、 サーバはBinding Error Responseを返さなければならない。 そのコードには431を含まなければならない。 Binding Error ResponseはBinding Requestの送信元IPとポート番号の組に返さなければならない。

メッセージの完全性チェックをパスした場合、処理を継続する。 サーバはリクエストの全てのattributeが、0x7fff以下であることをチェックしなければならない。 一つでも該当する場合は、サーバはBinding Error Responseを返さなければならない。 そのコードには420を含まなければならない。

中略

  1. ユースケース

8章及び9章の記述は、クライアントとサーバがどのようにふるまうかを記述している。 しかしながら、それらではどのようにSTUNプロトコルが利用されるかを推測することができない。 それはクライアントの自由裁量に依存する。 ここでは、いくつかの有用なSTUN利用シナリオについて記述する。

10.1 発見プロセス

このシナリオでは、ユーザは、以下のシナリオのうちのいずれかが当てはまるようなマルチメディアアプリケーションを動作させている。

・インターネット上で動作する ・ファイアーウォールがUDPをブロックする ・ファイアーウォールがUDPのアウトバウンドを許可しており、そのアウトバウンドの送信元へ帰ってこなければならない。 (シンメトリックNATでそうであるように。但し、アドレス変換は行わない。これをシンメトリックUDPファイアーウォールと呼ぶ) ・フルコンNAT ・シンメトリックNAT ・制限コーンNAT, ポート制限コーンNAT

上記の6シナリオが当てはまるアプリケーションは、図2に記述するフロー図で判断することができる。 この図ではBinding Requestのシーケンスだけで参照される。 Shared Secret Requestは、もちろん、それぞれのBinding Requestのシーケンスにおいて認証が必要である。

このフローは3つのテストを利用する。テスト1では、クライアントはSTUN Binding Requestを、 CHANGE-REQUEST attributeのフラグを一切立てず、 RESPONSE-ADDRESS attributeを設定せずにサーバへ送信する。 これにより、サーバはリクエストの送信元IPとポートにレスポンスを返信する。 テスト2では、クライアントはBinding Requestに”Change IP”と”Change port”フラグを両方セットして送信する。 テスト3では、クライアントはBinding Requestに”Change port”フラグのみをセットして送信する。

クライアントはテスト1から開始する。このテストでレスポンスを得られない場合、クライアントはUDP接続性がないことを認識できる。 レスポンスが得られた場合、クライアントはMAPPED-ADDRESS attributeを確認する。 アドレスとポートがローカルIPとポートと一致している場合、クライアントはサーバとNATを経由せず通信が行える。 次にテスト2を実行する。

レスポンスが得られれば、クライアントはインターネットに直結されている(か、少なくとも、アドレスを変換以外はフルコンNATと 同様のふるまいをするファイアーウォールの背後に居る)ことがわかる。 レスポンスが得られない場合、クライアントはシンメトリックUDPファイアーウォールの背後に居ることがわかる。

テスト1でMAPPED-ADDRESS attributeのIPアドレスとポートがソケットのものと一致しない場合、 クライアントはNATの後ろにいることが分かる。 次にテスト2を行う。 テスト2でレスポンスが得られた場合、フルコンNATの後ろにいることが分かる。 レスポンスが得られない場合、テスト1を再度実行する。 今回は前回のテスト1で帰ってきたレスポンスのCHANGED-ADDRESS attributeから得られたアドレスとポートに対してリクエストを送信する。 帰ってきたレスポンスと前回のレスポンスでMAPPED-ADDRESSが一致しない場合、シンメトリックNATの後ろにいることがわかる。 もしアドレスとポートが一致する場合、クライアントは制限コーンNATかポート制限コーンNATの後ろにいることが分かる。 これらのどちらかを決定するため、テスト3を実行する。 レスポンスが得られれば、制限NATの後ろであり、レスポンスが得られなければポート制限NATの背後である。

この手順はクライアントアプリケーションの実行状況について、充分な情報をもたらすことができる。 複数のNATがクライアントとインターネットの間に存在する場合、最も制限が厳しいNATの結果がもたらされる。 制限の厳しい順に、シンメトリック、ポート制限コーン、制限コーン、フルコンの順である。

概ね、クライアントは、変化を検出する、もしくは結果の不一致を探すために、 この発見プロセスを定期的に再実行する。 いつこのプロセスが再実行されるかを認識することは重要で有り、 一般的には、前回のプロセスと同一のローカルアドレスとポート番号を用いて再実行すべきではない。 同一のアドレスとポートが再利用されると、前回のNATバインディングが残っている可能性があり、 テストの結果が不正確になる可能性がある。 異なるローカルアドレスとポートを用いれば、次の試験でこの問題を回避することができる。 もしくは前回のバインディングがタイムアウトするのに充分に長い時間待機した後で実行すればよい。 (30分以上は待つべきである)

                    +--------+
                    |  Test  |
                    |   I    |
                    +--------+
                         |
                         |
                         V
                        /\              /\
                     N /  \ Y          /  \ Y             +--------+
      UDP     <-------/Resp\--------->/ IP \------------->|  Test  |
      Blocked         \ ?  /          \Same/              |   II   |
                       \  /            \? /               +--------+
                        \/              \/                    |
                                         | N                  |
                                         |                    V
                                         V                    /\
                                     +--------+  Sym.      N /  \
                                     |  Test  |  UDP    <---/Resp\
                                     |   II   |  Firewall   \ ?  /
                                     +--------+              \  /
                                         |                    \/
                                         V                     |Y
              /\                         /\                    |    Symmetric  N  /  \       +--------+   N  /  \                   V
  NAT  <--- / IP \<-----|  Test  |<--- /Resp\               Open
            \Same/      |   I    |     \ ?  /               Internet
             \? /       +--------+      \  /
              \/                         \/
              |                           |Y
              |                           |
              |                           V
              |                           Full
              |                           Cone
              V              /\
          +--------+        /  \ Y
          |  Test  |------>/Resp\---->Restricted
          |   III  |       \ ?  /
          +--------+        \  /
                             \/
                              |N
                              |       Port
                              +------>Restricted

             Figure 2: Flow for type discovery process

10.2 Bindingの生存時間の検出

STUNはNATのバインディングが残る時間の長さを検出することも可能である。 多くのケースで、クライアントはバインディングし続けるために、 新たなSTUNリクエストやアプリケーションパケットの送信によりバインディングを更新しなければならない。 バインディングの生存時間を検出することで、どの程度頻繁に更新しなければならないかを知ることができる。

バインディングの生存時間を検出するには、まず特定のソケットXからBinding Requestをサーバに送信する。 これはNAT上に一つのバインディングを生成する。 サーバからのレスポンスはMAPPED-ADDRESS attributeを含んでおり、 public IP addressとポート番号を知ることができる。 これらをそれぞれPaとPpと呼ぶ。 T秒間のクライアントはタイマーを開始する。 このタイマーが発火すると、クライアントは同一の宛先アドレスとポートに対して、 別のソケットYを用いて、別のBinding Requestをサーバに送信する。 このリクエストのRESPONSE-ADDRESS address attributeには、PaとPpを含む形で送信する。 これはNATの新たなバインディングを生成し、STUNサーバから古い方のバインディングに対して、 Binding Responseを送信する。 もしクライアントがSocket XでBinding Responseを受信すれば、バインディングは期限切れになっていない。 もしクライアントがsocket YでBinding Responseを受信するか (これは古いバインディングが期限切れになっており、NATが新しいバインディングを以前と同じものを割り当てた場合に起こりうる) レスポンスが得られない場合、バインディングは期限切れになっている。

レスポンスが得られればTを延長し、得られなければTを短縮する形で、 Tを変更して二分探索することにより、クライアントはライフタイムを知ることができる。

この発見プロセスは少し時間がかかる。 このプロセスは、通常デバイスが起動した瞬間にバックグラウンドで起動されるものである。

クライアントがこのプロセスを実行し、不一致な結果を得る場合があり得る。 例えば、NATがリブートされた場合や、何らかの理由でリセットされた場合、 プロセスは実際よりも短い時間を得ることになる。 この理由により、アプリケーション実装はこのテストを何回も実行し、 不一致な結果が得られることを予想しておくことを推奨する。

10.3 バインディングの習得

VoIP phoneのケースをもう一度考えてみよう。 環境を認識するため、起動時に発見プロセスを実行する。 そして今電話をかけたい。 発見プロセスの一部により、VoIP phoneはフルコンNATの後ろにいることが分かっている。

この電話は2つの論理的に分類されたコンポーネントによって成り立っている。 シグナルを取り扱うコントロールプレーンと、 音声やビデオ、RTPを取り扱うメディアコンポーネントである。 両方とも同じNATの後ろに居る。 コントロールとメディアに区分されている理由は、 それらの間でやりとりされる情報を最小化したいからである。 実際、これらは同一ホスト上で実行しなくてもよい。

音声通話を行うため、音声を受け取るために、通話のセットアップメッセージをやりとりする必要があり、 電話はIPアドレスとポート番号を知る必要がある。

アドレスを知るために、コントロールコンポーネントはShared Secret Requestを送信する。 Binding RequestにはCHANGE-REQUEST attributeもRESPONSE-ADDRESSも設定しない。 Binding Responseはmapped addressを含んでいる。 コントロールコンポーネントは、次のBinding Requestを生成する。 このリクエストには、前回受け取ったBinding Responseに含まれるmapped addressを設定したRESPONSE-ADDRESSを含む。 このBinding RequestはSTUNサーバのIPアドレスとポート番号と合わせてメディアコンポーネントに渡される。 メディアコンポーネントはBinding Requestを送信する。 STUNサーバへ送信され、Binding Responseがコントロールコンポーネントに帰ってくる。 コントロールコンポーネントはこれを受信し、 メディアコンポーネントに割り当てられたアドレスとポート番号を知る。

クライアントはmapped addressを通じて、どこからでもメディアを受信できる。

無音抑制のケースでは、メディアを受信しない期間が存在する。 このケースでは、UDPバインディングはタイムアウトするかもしれない。 これを取り扱うため、アプリケーションは定期的にバインディングをリフレッシュするため、 クエリを送信しなければならない。

マルチメディアセッションの参加者両方が同一のNATの後ろにいても可能である。 このケースでは、この手順を両者が行い続け、 publicアドレスのバインディングを把握しつづける。 メディアを相手に送信するとき、NAT経由で折り返し、相手に届く。

これはとりわけ効率的ではないし、不幸なことに、多くの商用NATでは動作しない。 このようなケースでは、クライアントはプライベートアドレスを利用して接続を再度試みる必要がある。

Written on August 16, 2013