スキップしてメイン コンテンツに移動

投稿

1月, 2014の投稿を表示しています

P2P探訪 StunでNat越え その5

フルコーン意外は上手く通信できない NATにもさまざまな特徴がある事が理解していただけたでしょう。 具体的に、各特徴ごとに通信可能か確認してみましょう。
フルコーン <---------> フルコーン フルコーン <---------x 制限付き フルコーン <---------x シンメトリック 制限付き    x---------x 制限付き
といった感じで、フルコーンNATでなければ、受信が困難な事がわかります。
UDPパンチなら一部回避できる しかし、UDPホールパンチングというテクニックを使えばこの制限を一部回避 する事ができます。
フルコーン <---------> フルコーン フルコーン <---------> 制限付き 制限付き    <---------> 制限付き フルコーン <---------x シンメトリック
といった感じです。
前もってメッセージを送信してもらう 制限付きNATは、「送信した事がある相手からのメッセージを受け付ける」、「送信した事がない相手からのメッセージは受け付けない」を満たすように設計されています。
そこで、UDPパンチでは、これからメッセージを送ってくる相手へ、「あらかじめメッセージを送信しておく」ことで、この問題に対処しています。 相手にメッセージを送った実績があれば、制限付きNATが通信をフィルタリングすることはありません。相手からのメッセージは制限なく自分に届きます。

そもそも、UDPにおいては、通信に失敗したかどうかをNATは判断できません。 なので、 NATからは、受信したメッセージが「通信相手からのレスポンスなのか」、「新規のメッセージなのか」を判断するすべはありません。
例 ※ d1とd2は異なる端末とします。
----------------------------------------------- KyoroDatagramMock d1 = new KyoroDatagramMock(KyoroDatagramMock.NAT_TYPE_RESTRICTED_PORT);KyoroDatagramMock d2 = new KyoroDatagramMock(KyoroDatagramMock.NAT_TYPE_RESTRICTED_…

P2P探訪 STUNでNat越え その4

まずは、スーパーノード候補として最有力なNATであるか調査してみましょう。 外部から見えている、「アドレスとポート」が常に一定であり。 他からのアクセスを制限していないNATのことです。(フルコーン)

○STUNでの確認方法  どのようにして、制限があるかを確認するのでしょうか? STUNの仕組みはとても単純です。実際に通信してみて各種条件で通信ができるか試します。実際に試してみて、もしも通信できたならば、同一の条件下の端末とは通信可能といえるでしょう。

具体的には、実際に外部からメッセージを送信してもらう。そして、送信しもらったメッセージを受け取る事ができるかを確認します。
接続したUDPサーバーから、メッセージを受け取れる事接続したUDPサーバーの異なるポートから、メッセージを受け取れること接続したUDPサーバーと異なるサーバーから、メッセージを受け取る事ができる事


○Bindingリクエスト  実際にSTUNの通信内容を見ていきましょう。サーバーにレスポンスする条件(ポートとアドレス)を指定してレスポンスを返しもらいます。このレスポンスの依頼をSTUNでは、Bindingリクエストと読んでいます。
 例えば以下のような、依頼を出す事でしょう。 CL はサーバーへ「受け取ったサーバーから、レスポンスを返してもらう。」依頼をだす。CL はサーバーへ「受け取ったサーバーから、ポートだけ変えてレスポンスを返してもらう。」依頼をだす。CL はサーバーへ「受け取ったサーバーから、ポートとアドレスを変えてレスポンスを返してもらう。」依頼をだす。

 3のレスポンスを受け取る事ができたならば、「フルコーン」といえます。


○ 実際に送受信するメッセージ STUNではBindingリクエストと呼ばれるリクエストほをサーバーへサーバーへ送信します。

1. 送信先のアドレスとポートから返信するように依頼をだす。 { 0x00, 0x00,   // 最初の2byteは0 0x00, 0x01,   // Binding リクエストを意味する 0x01  0x00, 0x08,   // Attrinuteのサイズ 8バイトを表す 0x08 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, // 16バイトのid 0x00, 0x03…

P2P探訪 STUNでNat越え その3

STUNサーバーをつくりながら、NATの構成を推測する方法を解説していきます。 ※ 制限のあるNAT配下で、通信をできるようにする方法については、後回しにします。 気になる方は「udp hole punching」とかで検索してください。
○もっとも厄介な制限 もっとも、厄介な制限はなんでしょうか? それは、UDPの使用に制限がかかっている場合です。 まずは、UDPの使用をできる事を確認してみましょう。

○サーバーに問い合わせて確認する  UDPの使用に制限があるかはアプリからは判断できません。なぜならば、 制限を加えているのは、主にルータだからです。なので、実際に外部のUDPサーバーと通信してみるより方法がありません。   外部のUDPサーバーに アクセスしてみて返答があれば、UDPが使える。返答がなければUDPが使えない。として判定できます。


○ 作った見よう  本書では、NAT越えをじょじょ広げていき、Stunにサーバーもどきを作っていきます。ただ、UDPが使用可能かのチェックをするのに必要な最小のこ構成は、「外部に返答を返すUDPサーバーを用意する」だけです。  早速用意してみました。
 やった事 Serversman で、vpsを借りる。     stunを実現するには、ipアドレスが2つ必要です。Standardプラン以降のものを準備する必要があるでしょう。もちろん、P2Pアプリとして実現するのであれば、Entryプランを2つ取得しても良いでしょう。http://kyorohiro.blogspot.jp/2013/07/blog-post.html
確認用に作成したコード サーバーから見えているクライアントのアドレスとポートを返すだけのアプリです。    https://github.com/kyorohiro/Hetimatan/blob/master/Hetimatan/src_nat/net/hetimatan/net/stun/HtunServer.java

○ 次回   Stunもどきの判定能力をじょじょにあげていたいと思います。次回はフルコーンNATかを判定してみる予定です。



P2P探訪 STUNでNAT越え その2

中継サーバーを間におく事で、お互いのアドレスとポート番号を特定する事ができまはた。UDPをSocketを使用して、通信してみましょう。しかし、残念ながら、多くの皆さんは通信に失敗する事でしょう。

<後述するような中継サーバー(P2PTracker)を試してみましょう>

ルータの制限なぜだ? UDPならばできそうなものだが? 「アドレスとポートから送り先をたどれない」ならば、そもそもUDPでの通信ができないではないか?
 そもそも、UDPはTCPと違いコネクションを持ちません。UDPは通信相手もUDPパケットに含まれるアドレスとポート番号を頼りにして相手と通信をします。
 ですから、「UDPパケットを受け取ったサーバー」と「そのサーバーからパケット情報をもらったクライアント」では、差が無いように思えます。


残念ながら、ルータによって制限がかけられています。 残念ながらルータには制限がかけられている場合があります。UDPの通信の仕組みはどうあれ、「UDPで送ったパケットを返信するのは、送った先の端末から」なのです。
ルータ制作者の立場にたってみれば、それ以外を想定する必要はないでしょう。


例えば、通信した「相手のアドレス」意外は不正な通信の可能性が高いとみなして、パケットを破棄する。(制限付きNAT)
例えば、「通信した相手のポート番号」意外は不正な通信の可能性が高いと見なして、パケットを破棄する。
※ 制限している訳では無くて、効率の問題でそうなっているだけかも知れません。

そもそも、UDPの本来の目的を満たすだけならば、送信相手によって、アドレスとポートを変えても良いでしょう。(シンメトリックNAT)

まとめ/次回予告 UDPに制限がある事を理解して頂けたことでしょう。 次回は、「制限を突破する方法」または、「制限の種類を特定する方法」について解説して行きたいと思います。



サンプルコード ○中継サーバーimport java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.Inet4Address; import java.net.UnknownHostException; import java.util.Linke…

P2P探訪 STUNでNAT越え その1

UPnPを用いて、NAT越えできました。しかし、ルータがUPnPをサポートしていなかったり。UPnPだけでは越えられないNATがあります。

本文では、その代案として前回解説できなかった。「適当なサーバーに接続してみて、相手から見えているアドレスを返してもらう方法」について解説していきます。

TCPの限界 インターネットで公開されている情報のほとんどは、TCPという通信方法でデータをやり取りされています。ですから、インターネットで情報を公開したい場合は、TCPサーバーを立ち上げる事を考える事でしょう。
 しかし、ルータがUPnPをサポートしていない場合、TCPを用いたサーバーを運用する事は困難になります。※ 基本、無理と考えもらって問題ありません。


接続相手から教えてもらう方法はどうした? 適当なサーバーに接続してみて、相手から見えているアドレスを返してもらう事で実現できないのでしょうか。前回はできそうな事を臭わせていました。しかし、TCPにおいて、これは困難です。

実際にTCPのプログラムを書き確認して見ましょう。接続相手のホストアドレスは推測できます。しかし、ポート番号を知るすべはありません。


import java.io.IOException; import java.net.Inet4Address; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; public class TCPTest { public static void main(String[] args) { TCPTest test = new TCPTest(); test.startServer(); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } test.startClient(); } private Server mServer = new Server(); public void startServer() { mServer.start(); } public v…

P2P探訪 UPnPでNAT越えする

P2Pアプリは、サーバーとクライアントの両方機能をもったアプリです。基本的には、各言語のServer用のSocketでプログラムを書くことでこのサーバー部分の機能を実装できます。しかし、ご家庭の端末はそれだけでは実現できない事があります。


○  NATの弊害
 「端末から見えている自分のIP」と「通信相手から見えている自分のIP」がことなる場合があるからです。※ 異なるのが普通と事と考えてもよいでしょう。
 サーバーとしての機能を活用するためには、相手に自分のIPを伝える必要があります。そもそも、相手が自分のIPを知らないと、接続してもらえません。



○ 相手から見えているIPを知る方法 そこで、相手から見えているIPを調べて、相手に通知してあげましょう。そうすれば、サーバーとして機能を果たす事ができます。

相手から見えているIPを知る方法はいくつかあります。
* a. ルータに確認する
* b.適当なサーバーに接続してみて、相手から見えているアドレスを返してもらうぬ
などです。


ここでは、「a.ルータに確認する方法」について紹介します。


○ UPnPを使おう ルーターとは、UPnPプロトコルを通して会話する事ができます。

1 "239.255.255.250" 1900に参加する
例えば以下のような感じ
<pre>
MulticastSocket ssdpSocket = null; InetSocketAddress ssdpGroup = new InetSocketAddress("239.255.255.250", 1900); InetAddress nicAddress = InetAddress.getByName(hostName); ssdpSocket = new MulticastSocket(new InetSocketAddress(nicAddress, SSDP_PORT)); ssdpSocket.joinGroup(ssdpGroup, NetworkInterface.getByInetAddress(nicAddress));
</pre>
2. ルータを探す UPnPは同一ネットワーク(ルータ内)のコンピュータへ、「M-SEARCH」をブルードキャスト送信する事で実現で…