2013-07-01

xkcd: ファイル転送(と、その解決手段としてのTCP simultaneous openの可能性)

xkcd: File Transfer

親戚にファイルを送ってもらいたいって? 簡単だよ、メールで・・・え、25MBだって。そっかー。
どっちかFTPサーバー持ってる? 持ってない? そっかー。
Webホスティング使ってるならアップロードして・・・
うーん、どっかのMEGASHAREUPLOAD的なサイトもあるんだけど、あの手のはいまいち信頼性にかけるしエロサイト広告満載だし。
AIMダイレクトコネクトはどうだい。え、そんなのいまどき誰も使ってないって?
そうだ、Dropboxがあった。数年前に始まったよさげなスタートアップでね、コンピューター間でフォルダを同期してくれるんだ。ただアカウントとってインストールして・・・
え、ちょうど親戚がUSBディスクもって家まで車でやってきた?
まあ、それもひとつの手だね。

もうインターネットは数十年もあるのに、「ファイルを送る」という事に関して、いまだに決定的な方法がないのは笑える。

一般人が、インターネット越しにファイルをやり取りするのは、意外と難しい。一般人は自前のサーバーなど持っていないし、レンタルサーバーを借りているなどという事もない。

ファイルのアップロードサイトは多数あるが、どれも微妙で、しかもエロサイト広告やマルウェアのインストールを促すような広告で溢れかえっている。個人間でのファイルのやり取りにはあまり向いていない。

AIMとかIRCなどは、とっくに一般人には廃れている。

Dropboxのような複数のコンピューター間でのファイル同期サービスもあるが、まずアカウントを取得して専用の不自由ソフトウェアを使わねばならず、しかも動作は第三者のサーバーに依存する。

結局、ストレージを足で運ぶスニーカーネットに負けてしまう。

現状で、インターネットの末端のホスト同士が直接接続して通信するのは、とても難しい。直接接続してファイルを転送するようなソフトウェアはあるが、まず、お互いに何とかしてIPアドレスとポート番号を教えなければならない。

しかも最近はNATの普及により、直接接続が一層難しくなっている。NATの設定には知識が必要だし、自分が管理者であるのならばまだしも、自分がNATを設定する権限を持たない場合は、どうしようもない。

もちろん、NATを超える技術はいくつも考案されているし、第三者のサーバーに依存しない、すなわちP2Pのファイル共有プロトコルも多数考案されているが、やはり特定の二者間でファイルを転送するには、時間や手間がかかりすぎるプロトコルが多い。

なぜこのxkcdを今更訳したのかというと、Hacker NewsでTCP simultaneous openの仕様が話題になっていたからだ。

TCP simultaneous open and peer to peer networking | Hacker News

TCP simultaneous open and peer to peer networking

TCPで、ふたつのホストがお互いのIPアドレスに、ephemeralポート以外のポートを使って、お互いに同時に接続要求をかけた場合、なんと一本の接続として成立するのだという。これは仕様上明確に定められており、お互いに自分からの接続なので、NATを超えることができる。

問題は、同時に接続というのが難しい。同一のLAN内だと、あまりのレイテンシーの低さに、タイミングがシビアすぎて失敗してしまう。また、予期しない接続要求に対してRSTパケットを送り返すデバイスが間にある場合にも、うまく行かない。

しかし、末端の一般人のインターネット越しの通信では、レイテンシーが高いため、同時接続要求が成立するタイミングは何度か試せば成功するほどの高確率であるし、また個人用のルーターでは、どこの馬の骨かもわからないホストからの予期しない接続要求に対して、わざわざRSTパケットを律儀に送り返す実装をしているようなものもほとんどないらしい。つまり、TCP simultaneous openは十分に実用的に使える可能性がある。

つまり、IPアドレスとポートを何らかの方法でお互いに知ることが出来れば、TCP simultaneous openでNAT越しにも接続できる。IPアドレスのマッチングは、それほど帯域を利用しないので、第三者サーバーで実装するコストも安く済む。

と、TCP simultaneous openはなかなか面白い仕様なのだが、現実には全然使われていない。NAT越えを考慮したP2Pプロトコルでも、UDP hole punchingを使うことが多い。

UDP hole punchingもまた面白い技法だ。これは仕様上保証された技法ではない。もとより、NATがどのように実装されるかということについての仕様などない。

NATの実装で一般的な方法は次のようなものだ。NATは外からのパケットは基本的に弾く。ただし、NATの内側のあるホストから、外側のあるホストへのパケット送信があった場合には、外側のホスト情報と、内側のホストとその時に使ったポート情報を記録しておく。この記録は、ふたつのホスト間の最後の通信からしばらくの間(数十秒から数分)、持続する。外側から特定のポートに対してパケットが送られた場合、この記録に対応する内側のホストがあれば、そのホストにパケットを届ける。

ほとんどのNAT実装で、UDPの場合は、外側からの任意のホストからのパケットを受け付ける。つまり、NAT越えをしたい内側のホストは、一体別の第三者サーバーにUDPパケットを送信する。これによりNATにしばらく記録が残る。その記録が残っているうちに、本当に通信したい別のホストがNATのIPアドレスのそのポートに対してUDPパケットを送りつける。NATの実装にもよるが、結構な実装で動く。

No comments: