Remote.It接続はどのように確立されるのか
以下の表1にあるラダーダイアグラムは、基本的なRemote.It接続に対応しています。この例のラダーダイアグラムは、sshコネクションを運ぶ暗号化されたRemote.It P2P UDPトンネルの確立に対応しています。このラダーダイアグラムは、接続時にエンドポイント間でやり取りされるUDPデータグラムのトラフィックを示しています。
このラダーダイアグラムは、特別に計測用に改造されたバージョンのRemote.Itソフトウェアを使い、発信元クライアント(私の自宅のノートパソコン)上でのパケットトレースから、Wiresharkによって直接生成されたものです。Remote.Itのネットワークトラフィックは暗号化されているため、データ、パケットタイプ、メッセージ、パケットフローはWiresharkやその他のパケット解析技術では確認できません。
ここに示されているのは、接続の開始から、両デバイス間でデータが流れ始める時点までの部分のみです。発信元クライアントのローカルアドレスは10.0.1.29(自宅の私のノートパソコン)です。この接続プロセスには2台のRemote.Itサーバーが関与しています。Remote.Itフロントエンドサーバーと、Remote.Itチャットサーバーです。Remote.Itフロントエンドサーバーのアドレスは174.36.235.146です。Remote.Itチャットサーバーのアドレスは209.235.201.53です。
ターゲットデバイスの外部IPアドレスは73.15.2.31(NATルーターの内側にあるオフィスのRaspberryPi)で、UDPポート55438を使用しています。これはNATルーターのIPアドレスであり、RaspberryPiの外部IPアドレスです。このラダーダイアグラムは発信元クライアント(自宅の私のノートパソコン)上でWiresharkにより生成されたものであるため、WiresharkにはRaspberryPiの内部IPアドレスを知る手立てがありません。RaspberryPiの内部IPアドレス(10.0.0.123)を知っているのはRemote.Itのみです。ラダーダイアグラム上にもRaspberryPiの内部IPアドレス10.0.0.123が表示されていますが、これについては後ほど説明します。
以下のラダーダイアグラムでは、矢印にはかっこ内に対応するUDPポート番号が付されているため、通常のラダーダイアグラムの慣例のように矢印の先端がエンドポイント(ラダーの両側)に接することはありません。これはWireshark(あるいはWiresharkでフローグラフと呼ばれるもの)がASCII版のラダーダイアグラムを生成する際の仕様によるものです。例えば、発信元デバイス(10.0.1.29の私のノートパソコン)との送受信トラフィックはUDPポート番号33013で表示されていますが、実際にはどのポート番号でも使用可能であり、この場合は発信元デバイスでRemote.Itソフトウェアを起動する際に指定できるものです。同様に、Remote.Itフロントエンドサーバー(174.36.235.146)のトラフィックはUDPポート番号5959で、Remote.Itチャットサーバー(209.235.201.53)のトラフィックはUDPポート番号5963で、RaspberryPi(外部アドレス73.15.2.31)はUDPポート番号55438でそれぞれ表示されています。
ここまで発信元デバイス(私のノートパソコン)と呼んできたものを、発信元クライアントと呼び始めたことにお気づきかもしれません。これは、私がRemote.Itユーザーとしてこの接続を開始しており、Remote.Itのログイン情報(user at remote.it)を使ってRemote.Itに対して認証を行っているためです。もしデバイス自体が接続を開始する場合には、その発信元を発信元クライアントではなく発信元デバイスと呼びます。Remote.Itはデバイス対デバイスの接続も行うことができ、その場合はユーザーログインを介さない、真の意味でのデバイス対デバイス接続になります。オフィスにあるRaspberryPiは、引き続きターゲットデバイスと呼びます。
以下のラダーダイアグラムでは、最初にやり取りされる4つのメッセージが、認証プロセスの一例です。Remote.Itは認証方式に柔軟性を持たせており、例えばOAuthやOAuth 2.0を使用することもできます。認証がどのように使われるかを示すため、ここではシンプルな例を示しています。認証は、発信元クライアント(または発信元デバイス)としてのユーザーの身元をRemote.Itサーバーに対して検証するために使用されます。認証では、Remote.Itサーバーが生成してクライアントに送信するノンス(1回限り使用されるランダムな数値)と、発信元クライアントとRemote.Itサーバーの間で共有されているシークレット(またはパスワード)を組み合わせてハッシュを生成します。このハッシュはRemote.Itサーバーに送られて認証され、送信されたハッシュがRemote.Itサーバー側で生成されたハッシュと一致すれば認証は成功します。認証に成功すると、共有秘密鍵、セッション鍵の暗号化、サーバー・クライアント間暗号化の鍵付けのための鍵が生成できるようになります。鍵の生成と交換の詳細については、その一部(すべてではありません)を以下で説明します。認証トラフィックは、以下のメッセージ説明においてAUのタグで示されています。鍵の交換が完了すると、それ以降のすべての暗号化メッセージトラフィックは、以下のメッセージ説明においてE1およびE2のタグで示されます。E1はサーバートラフィックの暗号化を示すために使用されます。E2はデバイス間のP2Pトラフィックの暗号化を示すために使用されます。E1とE2はそれぞれ別々の鍵と別々の暗号化方式を使用します。
以下のラダーダイアグラムにあるREQUEST_AUTH_MESSAGEなどのメッセージは、UDPデータグラム内に含まれるRemote.It CHATプロトコルのメッセージです。Remote.It CHATプロトコルは、Remote.Itがデバイスを接続する際に使用する基盤プロトコルです。各Remote.It CHATプロトコルメッセージにはパケットタイプがあります。この例のトレースでは、私が作成したカスタムのLua Wiresharkディセクターによって、Remote.It CHATプロトコルメッセージのタイプがデコードされており、そのためラダーダイアグラム上でメッセージタイプを確認することができます。改めて強調しておきますが、Remote.Itのトラフィックは暗号化されているため、この例で使用したような特別バージョンのRemote.Itデバイスソフトウェアがなければ、通常は見ることができません。
以下のラダーダイアグラムでは、接続開始からの経過時間(秒)がラダーダイアグラムの左側に示されています。このシンプルな例では、接続の開始とは、発信元クライアント(10.0.1.29の私のノートパソコン)上でRemote.Itソフトウェアが起動された時点を指します。

ここで理解しておくべき重要なコマンドが2つあります。スクリプトsshw.16.shは、既知のユーザーと、私が所有していて接続権限を持つ既知のデバイス(RaspberryPi)を対象に、Remote.Itソフトウェアを起動します。このデバイスはRemote.Itに「B2 RPi3 v1 ssh」という名前で登録済みのRemote.Itサービスとして認識されています。このサービスは私がRemote.Itに登録したものであり、Remote.Itにはタイプssh、用途はssh接続用として認識されています。私はユーザー「pi」としてRaspberryPiに接続するよう指定しています。このスクリプトが「P2P tunnel connected on port 33013」と表示することに注目してください。これは、Remote.ItによってP2Pトンネルが確立され、そのトンネルを使ったssh接続がこれから進められることを意味します。次のコマンドは、Remote.It接続トンネル経由でssh接続してきた、リモートのRaspberryPiからのパスワードプロンプトです。このプロンプトが、あたかも127.0.0.1、つまりlocalhostアドレスへの接続であるかのように表示されている点に注目してください。localhostアドレスが表示されるのは、Remote.ItソフトウェアがTCP接続を終端し、その後別のlocalhost接続を使ってTCPデータをホストに渡しているためです。localhostアドレスとlocalhostインターフェースを使用することで、外部からはlocalhost接続のみを許可すればよくなり、ホストを外部から完全に隠蔽(クローク)することができます。これはRemote.Itシステムの非常に重要な機能です。
以下のラダーダイアグラムでは、確立されたRemote.It接続上でデータが流れ始める時点までのRemote.It接続プロセスが示されています。完全なRemote.It接続セッションでは、sshがRemote.It接続経由でデータを転送する間、TUNNEL_DATA_MESSAGEとTUNNEL_ACK_MESSAGEのやり取りがさらに何度も発生します。最後に、接続が終了する際にも(例えば私がRaspberryPiのシステムプロンプトで「exit」と入力するなどして)いくつかのメッセージがやり取りされます。

表1. 基本的なRemote.It接続がどのように確立されるかを示すラダーダイアグラム。発信元クライアントのローカルアドレスは10.0.1.29(ノートパソコン)です。Remote.Itフロントエンドサーバーのアドレスは174.36.235.146、Remote.Itチャットサーバーのアドレスは209.235.201.53です。ターゲットデバイス(RaspberryPi)の外部アドレスは73.15.2.31、内部アドレスは10.0.0.123です。このラダーダイアグラムは、特別バージョンのRemote.Itソフトウェアを使用して発信元クライアントデバイス上で取得したパケットトレースから、Wiresharkによって直接生成されたものです。

表2. 基本的なRemote.It接続におけるメッセージ内容と機能。上記の表の各行は、ラダー表1の各行に対応しています。両方の表を並べて見ることで、各Remote.It CHATプロトコルメッセージのタイミング、方向、エンドポイント、機能を横断的に把握することができます。
Remote.It接続メッセージ
ここからは、上記のラダーダイアグラムに含まれる各Remote.It CHATプロトコルメッセージにおける情報の流れを、より詳しく見ていきます。以下の各Remote.It CHATプロトコルメッセージは、上記のラダーダイアグラムの各行に対応しています。以下では上記よりも多くのメッセージ内容を追加していますが、それでもすべての情報が示されているわけではありません。例えば、接続や利用に関する制限、各種の製造・展開オプションなどは、接続確立の仕組みを理解する上で本質的でない場合には示していません。
(REQUEST_AUTH_MESSAGE) AU: これを含め、最初にやり取りされる4つのメッセージは、セキュアな認証のシンプルな例であり、これら4つのデータグラムには「AU」のフラグが付けられています。これは私のノートパソコンからRemote.Itフロントエンドサーバーへのメッセージで、「私はm*****@remote.itです」という内容と、この接続セッションを識別するために使用される一回限り生成された発信元クライアントUID、そして最後に接続した際のIPアドレスとポートを含んでいます。
(RESPONSE_AUTH_MESSAGE) AU: Remote.Itチャットサーバーの IPアドレスとポートへのリダイレクトです。加えて、Remote.Itフロントエンドサーバーから見たNATマップ済みIPアドレスとポートも含まれています。
(REQUEST_AUTH_MESSAGE) AU: 最初のREQUEST_AUTH_MESSAGEと同一の内容ですが、Remote.ItチャットサーバーのIPアドレスとポートへリダイレクトされています。
(RESPONSE_AUTH_MESSAGE) AU: Remote.Itフロントエンドサーバーから私のノートパソコンへのメッセージです。内容は、発信元クライアントUID、ノンス(一回限りのランダムな数値)、使用する暗号化方式、ログインソルト(暗号化前にデータに付加されるシード値)、そしてRemote.Itチャットサーバーから見たNATマップ済みIPアドレスとポートです。Remote.Itフロントエンドサーバーから見たNATマップ済みIPアドレスとポート、およびRemote.ItチャットサーバーからみたNATマップ済みIPアドレスとポートは、両方合わせてRemote.ItがNATのタイプを判定するために使用されます。
(IDENTIFICATION_MESSAGE) E1: これ以降、すべてのRemote.Itサーバートラフィックは暗号化されている点に注意してください(この暗号化方式で暗号化されたすべてのデータグラムにはE1のフラグが付けられています)。内容は、SPI、パケットソルト、(認証ハッシュ)、(シーケンス番号)。()は未使用を意味します。加えて、ローカルIPアドレスとポート、NATタイプ、クライアントフラグ(製造ID等)、プロトコルサポート(TCPトンネル)、サポートされるP2P暗号化、利用制限です。
(ACK_MESSAGE) E1: 内容は、SPI、パケットソルト、セッション制限です。
(REQUEST_P2P_MESSAGE) E1: 内容は、SPI、ソルト、ターゲットデバイスUID(データタイプ0x0a)、発信元クライアント(私)のUID(データタイプ0x01)、発信元クライアントがサポートする暗号化方式、NATタイプに応じて必要となる予測ポート、利用制限です。これは重要なメッセージで、私が接続したいターゲットデバイスのUIDが含まれています。
(INITIATE_P2P_MESSAGE) E1: 内容は、SPI、ソルトです。信頼性と速度を考慮したチューニングの結果、同一のINITIATE_P2P_MESSAGEが2回送信される点に注意してください。内容は、SPI、ソルト、このセッションで使用する暗号化方式、セッションID、ターゲットデバイスUID、NATタイプに応じて必要となる内部IPアドレスとポート、利用制限です。
(INITIATE_P2P_MESSAGE) E1: このメッセージは最初のINITIATE_P2P_MESSAGEと同一です。注: 信頼性と速度のため、Remote.Itチャットサーバーからターゲットデバイスへ2つのINITIATE_P2P_MESSAGEが送信されます。
(P2P_HELLO_MESSAGE) E2: このメッセージは、ネゴシエートされた暗号化方式で暗号化されています。内容は、セッションID、ターゲットデバイスUID、発信元クライアントUID、最大パケットサイズ、バッファの深さに関連する最大未処理リクエスト数です。このメッセージはRemote.Itのみが知るRaspberryPiのローカルアドレス10.0.0.123への接続試行である点に注意してください。例えば、私のノートパソコン(10.0.1.29)が10.0.0.123へルーティングできるケースもあり得ます。しかし今回のケースではできません。この仕組みは、一部の特殊なNATおよびネットワーク環境において接続を可能にする上で重要です。
(P2P_HELLO_MESSAGE) E2: このメッセージは、発信元クライアントからターゲットデバイスへの最初のローカル接続用P2P_HELLO_MESSAGEと全く同じ内容ですが、今回はターゲットデバイスであるRaspberryPiの外部IPアドレス73.15.2.31宛てです。注: 発信元クライアントとターゲットデバイスのいずれか、先にP2P_HELLO_MESSAGEが届いた方によってP2P接続が完了します。
(P2P_HELLO_MESSAGE) E2: 発信元クライアントからのP2P_HELLO_MESSAGEと全く同じ内容ですが、UIDが入れ替わっています。
(ACK_MESSAGE) E2: このACK_MESSAGEによってP2P接続が完了します。完了しない場合はさらにP2P_HELLO_MESSAGEが送信されます。
(ACK_MESSAGE) E2: ACK_MESSAGEは両方向で流れる必要があり、それによって双方向のP2P接続が完了します。
(P2P_CONNECTED_MESSAGE) E1: このACK_MESSAGEは、接続が完了したことをRemote.Itサーバーに通知します。
(P2P_CONNECTED_MESSAGE) E1: 信頼性等のため、2つのP2P_CONNECTED_MESSAGEが送信される点に注意してください。
: 33013 → 5963 Len=1 U: これは、必要なルーターのNATテーブルパラメータが期限切れになるのを防ぐために、意図的にTTLを短く設定したパケットです。このパケットは実際にはRemote.Itサーバーには到達しません。
(TUNNEL_CREATE_MESSAGE) E2: このメッセージは、あらゆるTCP接続確立プロセスによってトリガーされます。例えば、sshが起動するとTCP接続が確立されます。このメッセージにより、既に確立済みの暗号化されたUDPトンネルの内部にTCPデータパイプが形成されます。各デバイス上のRemote.ItソフトウェアがTCP接続を終端する点に注意してください。TCPデータ(そしてTCPデータのみ)が、例えば127.0.0.1のようなアドレスを使ったlocalhost接続経由でホストに渡されます。したがって、Remote.It UDPトンネルの内部にはTCPヘッダーは存在しません。つまり、Remote.Itを介してTCPヘッダー情報が伝わることは一切ありません。これは、たとえ何らかの方法で複数層の暗号化が破られてTCPデータが露出したとしても、そのTCPデータを使ってできることは何もない、つまりルーティング可能な情報が存在しないということを意味します。
(TUNNEL_ACK_MESSAGE) E2: このメッセージは、暗号化されたRemote.It P2P UDPトンネルの作成に成功し、ターゲットデバイス上でTCP接続が確立されたことを確認応答します。確立されなかった場合はTUNNEL_CREATE_MESSAGEを再試行します。
(TUNNEL_DATA_MESSAGE) E2: このメッセージには、暗号化されたRemote.It P2P UDPトンネルの内部に、TCPデータ(TCPヘッダー情報を含まない、TCPデータのみ)が含まれています。
(TUNNEL_ACK_MESSAGE) E2: このメッセージは、暗号化されたRemote.It P2P UDPトンネル上でのデータのやり取りに対する確認応答を行い、フロー制御を伴うデータ交換を実行します。
Remote.Itに関するさらなる詳細
上記の接続ラダーダイアグラムに使用したWiresharkのトレースでは、UDPパケットの内容は表示していません。もしそれらのUDPデータグラムを表示していれば、TCPデータやTCP接続の詳細(フロー制御など)は確認できたはずですが、TCPヘッダー情報は一切確認できなかったでしょう。これは、たとえRemote.It接続内の複数層の暗号化が何らかの方法で破られたとしても、明らかになるTCPデータにはヘッダーがなく、したがってルーティング情報も存在しないため、利用できないということを意味します。
接続ラダーダイアグラムに使用したWiresharkのトレースでは、UDPパケットの長さや総データ使用量も表示していません。Remote.It CHATプロトコルは、非常に低いオーバーヘッドとなるよう設計されており、例えばデータ使用量のモニタリングを可能にするメッセージなども備えています。
接続ラダーダイアグラムに使用したWiresharkのトレースからは、Remote.It接続が127.0.0.1への接続であるかのように見える点は明らかではありません。これは、暗号化されたRemote.It P2P UDPトンネルの内部を通るTCP接続を、Remote.Itデバイスソフトウェアが終端していることによるものです。これは非常に重要な機能であり、ホストデバイスがすべてのポートをクローク状態のまま閉じることを可能にします。許可する必要があるのは127.0.0.1、あるいはその他のlocalhost接続のみです。