Teredo事始め

Windows Vistaならば、すぐに使い始めることが出来るが、XPだと、最初に初期化を行わなければならない。しかし、これはそんなに面倒ではなくて、コマンドプロンプトで、次のような一連の作業を行えばよい。

IPv6の有効化 (XPのみ)

C:\>ipv6 install
Installing...
Succeeded.

Teredoの初期化 (XPのみ)

これにはnetshを使う。

C:\>netsh
netsh>interface ipv6
netsh interface ipv6>set teredo client
OK

Teredoの動作状況確認

Teredoの動作状況を確認する方法。

netsh interface ipv6>show teredo
Teredo パラメータ
---------------------------------------------
種類                    : client
サーバー名              : default
クライアント更新間隔    : default
クライアント ポート     : default
状態                    : probe(cone)
種類                    : teredo client
ネットワーク            : unmanaged
NAT                     : cone

ちなみに、Windows Vistaだと表示内容が異なる。以下はVistaの場合。

netsh interface ipv6>show teredo
Teredo パラメータ
---------------------------------------------
種類                    : default
サーバー名              : teredo.ipv6.microsoft.com.
クライアント更新間隔    : 30 秒
クライアント ポート     : unspecified

TeredoのIPv6アドレス

TeredoのIPv6アドレスは、ipconfig /allで参照することが出来る。

Windows XPの場合。

Tunnel adapter Teredo Tunneling Pseudo-Interface:

  Connection-specific DNS Suffix  . :
  Description . . . . . . . . . . . : Teredo Tunneling Pseudo-Interface
  Physical Address. . . . . . . . . : XX-XX-XX-XX-XX-XX-XX-XX
  Dhcp Enabled. . . . . . . . . . . : No
  IP Address. . . . . . . . . . . . : XXXX:X:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
  IP Address. . . . . . . . . . . . : fe80::ffff:ffff:fffd%4
  Default Gateway . . . . . . . . . : ::
  NetBIOS over Tcpip. . . . . . . . : Disabled

Windows Vistaの場合。

Tunnel adapter Local Area Connection* 6:

 接続固有の DNS サフィックス . . . :
 説明. . . . . . . . . . . . . . . : Teredo Tunneling Pseudo-Interface
 物理アドレス. . . . . . . . . . . : XX-XX-XX-XX-XX-XX
 DHCP 有効 . . . . . . . . . . . . : いいえ
 自動構成有効. . . . . . . . . . . : はい
 IPv6 アドレス . . . . . . . . . . . : XXXX:X:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX(優
先)
 リンクローカル IPv6 アドレス. . . . : XXXX::XXXX:XXXX:XXXX:XXXX%XX(優先)
 デフォルト ゲートウェイ . . . . . : ::
 NetBIOS over TCP/IP . . . . . . . : 無効

見慣れないのでわかりにくいが、IP Addressまたは、IPv6 アドレスというところに書かれている : (コロン)で区切られた16進数値がアドレスだ。

ここで表示されるIPv6のアドレスは、自動的に仲介サーバーに登録される。Teredoのクライアントはこのアドレスを仲介サーバーに問い合わせることによって、接続相手を探す。当たり前ではあるのだが、これによってファイヤーウォールが骨抜きにされるので、下手をすると不特定多数に対してポートを開いているのと同じことになるのには注意が必要だ。

詳しくは、「KB817778: Advanced Networking Pack for Windows XP の概要」を参照。

Teredo

P2Pのアプリケーションを自分で作ろうと思うと、おそらく、NAT越えのための実装から始めなければならない。UDP Hole Punchingは比較的簡単に実装できるが、逆に問題は、UDPだと、通信の制御をほとんど自前で作成しないといけないことだろう。これは技術的には非常に楽しい部分ではあるが、単にP2Pの応用のアプリケーションを作ろうとしているプログラマにとっては、時間の浪費にしかならないかもしれない。できれば、誰かが作った似非TCPの実装を使いたい。

Windows XPWindows Vistaでは、実はこの面倒なレイヤーの実装がOSに同梱されている。TeredoというIPv6を使ってトンネリングをする技術である。そんなことを言っても、IPv4のアドレスしか持ってませんなんていう心配はない。この技術は、IPv4のネットワーク上で、IPv6の技術を用いているだけなのだ。この説明だけだと、なおさら???な状態だが、必要な知識はIPv6のアドレスがIPv4とは異なることぐらいで十分。それ以外はあえてブラックボックスだと思って使い始める方が良いぐらいかもしれない。

Teredoでの通信

Teredoでは、というか、Teredoに対応したIPv6アプリケーションでは、このIPv6アドレスに対して接続をすることになる。OSが全ての処理を隠蔽してくれるので、まるでグローバルアドレスを持っているかのような簡単さだ。

Windows Vistaに付属のリモート デスクトップ クライアントでは、標準でTeredoに対応しているみたいだ。ここにVistaのホストのTeredo IPv6アドレスを入力すると接続が出来る。しかしながら、何が原因なのか、ここをXPのホストにするとうまくいかない。

C#でコードを書けばXP側でのAcceptに対しても接続できるので、これの原因が何なのかは分からない。試しにファイヤーウォールをOFFにしてみたが、改善は見られなかったので他の理由なのだろう。

C#でコードを書いてみる。

コードを書くと言っても、実は全く難しいプロセスはない。ちょっとしたオプションをソケット(Socket)に対して指定するだけである。

Socket s = new Socket(
    AddressFamily.InterNetworkV6,
    SocketType.Stream,
    ProtocolType.Tcp);

// Teredoを有効にする
const int IPV6_PROTECTION_LEVEL = 23;
const int PROTECTION_LEVEL_UNRESTRICTED = 10;
s.SetSocketOption(
    SocketOptionLevel.IPv6,
    (SocketOptionName)IPV6_PROTECTION_LEVEL,
    PROTECTION_LEVEL_UNRESTRICTED);

たったこれだけ。後は普通のコードと同じ。NATに守られているはずのマシンの情報がWANに漏れることになるので、セキュリティに関しては若干の注意が必要だが、この手軽さは捨てがたい魅力だ。

自分に割り当てられたTeredoIPv6アドレスを取得する

普通はipconfig /allで確認することが出来るが、プログラムから取得するには、ちょっとだけ面倒なことをする必要がある。さらに、アダプタ詳細で判断して良いのかどうかは不明。

IPAddress GetTeredoIPv6Address()
{
    if(!NetworkInterface.GetIsNetworkAvailable())
        throw new ApplicationException("Network is not available!");
    
    if(!Socket.OSSupportsIPv6)
        throw new ApplicationException("IPv6 not enabled!");
    
    NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
    if(nics == null || nics.Length == 0)
        throw new ApplicationException("No network interfaces found.");

    foreach(NetworkInterface adapter in nics)
    {
        if(!adapter.Supports(NetworkInterfaceComponent.IPv6))
            continue;
        if(!adapter.Description.Contains("Teredo"))
            continue;
        IPInterfaceProperties props = adapter.GetIPProperties();
       foreach(UnicastIPAddressInformation uiai in props.UnicastAddresses)
       {
           IPAddress addr = uiai.Address;
           if(addr.IsIPv6LinkLocal || addr.IsIPv6SiteLocal)
               continue;
           return addr;
       }
    }
    
    throw new ApplicationException("Teredo adapter is not found!");
    return null;
}