こちらの情報は2016/7/11時点のものです。現在の最新版では状況が変わっている可能性がありますのでご注意ください。
問題
2016/06/01からiOSアプリでのIPv6(NAT64)ネットワーク対応が義務化されましたが、
UnityでSocketを使って下記のようなコードを書いていた場合、NAT64ネットワークで接続に失敗してしまいます。
var addresses = Dns.GetHostAddresses(hostnameOrIP);
if (addresses.Length > 0) {
var address = addresses[0];
var socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
var endPoint = new IPEndPoint(address, port);
socket.Connect(endPoint);
// socketを使った処理...
}
このプログラムをNAT64ネットワークで動かしてみると、
- ホスト名を指定した場合(eg.
hostnameOrIP="google.com"
)→ 問題なく動作する - IPv4アドレスを直接指定した場合(eg.
hostnameOrIP = "216.58.220.206"
)→ エラーが発生する
ホスト名でしかサーバへ接続しない場合は問題ないのですが、いろいろな事情によりホスト名のないサーバへ接続しなければならない場合はなにか対処を行う必要があります。
Appleの上記リンクでの説明のよればgetaddrinfo
関数をを使ってIPv4アドレスからIPv6アドレスをsynthesizeできるとのことです。しかしUnity C#上からはこの関数を直接呼び出すことができません。
対処
とりあえずなんらかの方法でgetaddrinfo
関数を呼び出す必要があります。
方法1. getaddrinfo
を呼び出すプラグインを作成する
Forumでプラグインを公開されてる方がいました。
これを使うことでC#上から間接的にgetaddrinfo
を呼び出し、IPv6アドレスを得ることができます。
方法2. Dns.GetHostAddresses
の代わりにDns.GetHostEntry
やDns.GetHostByName
などのメソッドを使う
Dns.GetHostEntry
やDns.GetHostByName
は内部でgetaddrinfo
を呼び出しているため、これらのメソッドを使うことでIPv6アドレスを得ることができます。
ただしこれについては下記のようなリスク・デメリットがあります。
- 公式に保証された動作ではないため将来的に予期せず変更の可能性がある
-
Dns.GetHostEntry
を呼び出すとDNS逆引処理が行われ、不要なオーバーヘッドが発生してしまう -
Dns.GetHostByName
は現在Obsoleteである
そのため基本的には方法1を使うようにし、方法2については個人での開発でアップデートの予定がないときなど極めて限定的なケースでのみの使用にとどめておいたほうが良さそうです。
64:ff9b::/96
をつける方法は駄目
なおMacのインターネット共有機能を使って作成したNAT64ネットワークでは、IPv4アドレスにプレフィックス64:ff9b::/96
をつける方法でもうまく動作させることができます。
ただしこのプレフィックスはネットワークによっては異なる可能性があり、推奨されていません。
詳しくはApple Developer Forumsの下記ページの#4を参照してください。
はい
ところでiOS9環境にてC#上でIPv4アドレスからIPv6アドレスへ変換する方法について、Xamarinが何か言ってないか/公式で用意していないかと探したんですが見つけられませんでした。Xamarin.iOSのアプリもSocket
使っていれば同じような問題に直面すると思うのですがどうなんでしょう?(試してない)(何か情報があれば教えてください)
Xamarinのアップデートで何か対応があったとしても、Unity側でそれが取り込まれるのははるか先のことだと思うのでおそらく意味ないのですが。
追記(2016/06/23)
Xamarinより言及がありました。
……が、言及されているMapToIPv6()が返すのは"IPv4-mapped address"で、Apple指定のNAT64環境で使える"synthesis"されたアドレスとは別のような? ちょっとよくわからないです。
どちらにしろUnityではMapToIPv6()は使えないのですが。