iOS9 以降で必要な IPv6 only Network への対応

iOS (9.0 以降) では DNS64/NAT64 という技術で構築された IPv6 ベースのネットワークでアプリが動くようにする必要がある。

本記事は、末尾の参考文献に記載された内容の意訳をベースにしている。

## 概要

- iPhone に対して IPv6 の通信環境しか提供しないキャリア(通信事業者)が今後登場する。
- 既存の IPv4 のホストと通信しようとした場合、キャリアのゲートウェイで IPv6 ⇔ IPv4 の変換が行われる (DNS64/NAT64)。
- (接続先がIPv4/v6のどちらであるかに関わらず) あなたのアプリが IPv6 環境で正しく動作するようにしなくてはならない。__これは審査でチェックされる__。

## 影響範囲は

- ネットワーク通信を実装したiOSアプリすべてで動作確認と、問題があれば改修を実施する必要がある。
- (iOS外で動作する) サーバサイドについては原則として影響を受けない。

## ネットワーク接続における変更点

今のところ iPhone は IPv4 と IPv6 の両方のプロトコルで接続されている。[^1]

この場合、あなたがサービスを IPv4 で提供しているのであれば IPv4 のインタフェースで接続が確立される。

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/ed10d486-79a7-a92b-306f-b388bb398a9f.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

近い将来、iPhone の接続先を IPv6 に完全移行する計画がある。移行は各キャリアやAppleの方針で行われるため、日本での導入がいつになるかはわからないが、iOS9 がこの形態のネットワークをサポートし、将来の移行を計画していることは発表されている。

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/fb80e954-e0f4-cfd1-cee9-763fa27ba540.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

この形式に移行した場合、たとえサービスを IPv4 だけで提供している場合であっても、iPhone は IPv6 プロトコルでホストに接続しようとする。

キャリアのゲートウェイには DNS の IPv4 応答を IPv6 に変換する DNS64 と、IPv6 の接続要求を IPv4 に変換する NAT64 が設置されることにより、IPv4 のあなたのサーバに接続できるようになっているため、ネットワーク (L3) レベルでの対応は特にいらない。

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/ec0e9ee1-cbfa-48b2-bab3-a4bc22dc342e.png)
出典: [Supporting IPv6 DNS64/NAT64 Networks - DNS64/NAT64 Transitional Workflow](https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW11)

## アプリへの影響

実は多くのアプリは、特に対策をしなくても NAT64 で問題なく動く。iOS が提供する高レベルの API のインタフェースは特に変わらないし、接続性についてもキャリア側が透過的に処理してくれるからだ。

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/eb70b2ea-3804-65a9-7ecc-187db229f9b7.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

しかし、以下のような実装があると、NAT64 (IPv6オンリー) に対応できなくなる。

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/651bd300-591d-51d5-2bc9-2e540a2fd484.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

- IPv4 を前提とした変数/構造体 (`uint32_t`, `in_addr`, `sockaddr_in`)
- IPv4 でしか使えない API (`inet_aton`, `gethostbyname`)
- IPv4 でしか正しく動作しない API の呼出 (`gethostbyname2(hostname, AF_INET)`)
- IPv4に依存したネットワークの接続チェックプロセスが存在する場合
  - デバイスが IPv4 アドレスを持っているか
  - 0.0.0.0 に接続できるか

そのようなチェックを実装していると、NAT64 環境では「ネットワークに接続できない」旨のダイアログを出し、アプリの動作が止まってしまうだろう。

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/c90cfb0e-94f8-6388-fdc6-c88973b32e67.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

## 実際の対処方法

まず、NAT64 の環境を用意する。

macOS 10.11[^2] 以降では NAT64 の WiFi アクセスポイントを作成する機能がついている。

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/d52c0a5b-83a9-695c-4118-9cbf5d9f7f65.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

システム環境設定の "共有" ボタンを [option] キーを推しながらクリックし、続いて "インターネット共有" を有効にする際、NAT64 をオンにできる[^3][^4][^5]。

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/f2ee179a-9042-4230-f852-bd5bf65a9fc5.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/2108/5541be8b-206c-a328-a9f1-416222e0204c.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

もしあなたのアプリが動かなくなった場合、以下の点に注意して実装を修正しよう。

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/c0c00648-d335-035e-3d1f-d25f168e42e6.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

- アドレスファミリに依存しない実装
  - 接続確認を事前にするのではなく、接続の失敗をハンドリングするように
  - `NSURLSession`、`CFNetwork` レイヤーの API を使うようにする
- [RFC4038](https://www.ietf.org/rfc/rfc4038.txt)(IPv6移行期におけるアプリケーションの実装)を参考にする
- [サービス名で接続するAPI](https://developer.apple.com/library/mac/documentation/Networking/Conceptual/NSNetServiceProgGuide/Articles/ResolvingServices.html#//apple_ref/doc/uid/20001078-SW7)を使う

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/ed07d96b-27ae-f3b3-4d38-33dd644f7a90.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

- 高レイヤのフレームワークを使う
  - `NSURLSession`、`CFNetwork` レイヤーの API 
- クライアントは IPv4 のアドレスリテラルを使うようにする
  - OS では IPv6 アドレスと統合して扱われる

## 対応期限

![image](https://qiita-image-store.s3.amazonaws.com/0/2108/63a8cf17-3185-ebcc-19f6-3fbd563247d1.png)
出典: [WWDC15 - Your App and Next Generation Network](http://devstreaming.apple.com/videos/wwdc/2015/719ui2k57m/719/719_your_app_and_next_generation_networks.pdf)

~~今年の終盤~~ ~~来年(2016年)初頭[^6]~~ __2016/6/1__[^7] から App Storeの審査でIPv6対応が要求されている。

## 参考文献

- [iOS Developer Library - Prerelease : Supporting IPv6 DNS64/NAT64 Networks](https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html)
- [WWDC15 - Session 719 : Your App and Next Generation Network](https://developer.apple.com/videos/wwdc/2015/?id=719)

## 個人的な感想

- 広告やアナリティクスなどのライブラリ、ゲームエンジンなど隠蔽されたAPIの内部実装によっても影響がでる話なので、もっと騒いだほうがいい。
- IPv6しかり、ATSしかり「インターネット的にはやらないといけない[^8]」「けど商業的なメリットがデベロッパーに見えない」修正をプラットフォームでごり押しするというのは、個人的にはよい気がする。無理矢理にでも誰かが音頭をとらないと、こういうのは話が進まない。

## 脚注

[^1]: 通信事業者(APN)によってはIPv4のみ提供している。日本のキャリアでは大多数(spモード,LTE NET,S!ベーシックパック)のAPNはIPv4のみを提供していて、IPv6を利用できるのは mopera U, LTE NET for DATA, IIJmio など一部に限られている。

[^2]: ~~執筆時点ではリリースされていないので、Apple Developer Program で入手するか、Public Beta版を用意する必要がある。~~ 現在は Mac App Store より無償でアップグレードできる (El Capitan または Sierra)。

[^3]: Macをルータとしてテザリングさせているような構成になる。iPhoneを接続させるネットワーク(LAN側)でWiFiを用いるので、WAN側として有線LANやBluetooth PANなどを用意する必要がある。

[^4]: WAN側はIPv4だけでよい(ふつうのプロバイダで大丈夫)。

[^5]: システム環境設定を開き、 option ボタンを押しながら "共有" → "インターネット共有" と進むことで、 NAT64 のオプションが表示される。

[^6]: 対応期限が今年の終盤から[2016年初頭に延期](https://developer.apple.com/news/?id=08282015a)された。

[^7]: [2016年6月1日から審査時にIPv6のテストが行われる](https://developer.apple.com/news/?id=05042016a)とアナウンスされた。

[^8]: IPv4 でインターネットを利用し続けることについて、現状では目立った問題が起きてはいないが、IPアドレスを複数人で共有するための装置(キャリアグレードNAT)の負荷からパフォーマンスへの影響も発生している。