IPv6 only Network上での通信周り挙動について

#概要
2016年初頭以降appleに申請を出すアプリに関して、義務付けられたIPv6対応に関する挙動が誤解されやすそうな気がするのでまとめる。


#テストした環境
下記に載ってる***Mac El CapitanにおけるDNS64/NAT64環境***で構築したwifiポイント。(今後長いのでMac El CapitanにおけるDNS64/NAT64環境のwifiポイント→***IPv6ポイント***、と呼びます)

[「Supporting IPv6 DNS64/NAT64 Networks」 / Apple](https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html)
[「iOS9 で必要な IPv6 only Network への対応」](http://qiita.com/shao1555/items/4433803419dfc72bf80b)

これ以外でもオープンソースでDNS64/NAT64の実装はあるみたいですが、iOS端末がIPv6環境に対応してなくても動くように中でIPv6をエミュレート、みたいな動きをするらしいので多分別物だと思います。

##クライアント端末
iOS9端末(iPad mini初代 A1432)

AndroidやiOS8端末、別のMac PCからIPv6ポイントにwifi接続しようとしても、認証に問題がありますと出て繋がらなかった

#IPv6OnlyNetwork上での通信周り挙動について

[Supporting IPv6 DNS64/NAT64 Networks](https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW11)に使うべきでない関数や定数などが列挙されています

##IPv6ポイントに接続したiOS9端末でIPv6アドレス確認
http://test-ipv6.com/
結果：IPv6 アドレスが検出されませんでした

※IPv6のない環境でアクセスしました

##IPv6ポイントからHTTPリクエスト
**NSURLSession**でIPv4アドレス直打ちのアクセス
curl http://123.45.67.89/と同じレスポンス返ってきた(Apacheのテストページ)

```objc
NSURL* url = [NSURL URLWithString:@"http://123.45.67.89/"];
    NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
     
    NSURLSessionDataTask* task =
    [session dataTaskWithURL:url
           completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
               NSString *str= [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
               NSLog(@"str -- %@", str);
           }];
     
    [task resume];
```

**NSURLSession**でIPv4のみのサーバーへアクセス
curl http://example.com/と同じレスポンス返ってきた

```objc
NSURL* url = [NSURL URLWithString:@"http://example.com/"];
    NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
     
    NSURLSessionDataTask* task =
    [session dataTaskWithURL:url
           completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
               NSString *str= [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
               NSLog(@"str -- %@", str);
           }];
     
    [task resume];
```

上記からObjective-Cの関数であれば大体何も考えなくてもAppleの審査は問題ないと思われます
※IPv4アドレス直打ちのリクエストはDNSを通していないので、そのまま繋がるみたいですが今後IPv4をなくす方向でAppleも動くはずなので出来れば変えた方が良いです

次C言語

**gethostbynameとinet_ntoaでIP取得**
Appleの公式では使っちゃダメって言われてるAPI
C言語なのでよく分かってませんが下記は通常通りの値が返ってくる

```c

    struct hostent *hostentry;
    hostentry = gethostbyname("google.com");
    char * ipbuf;
    ipbuf = inet_aton(*((struct in_addr *)hostentry->h_addr_list[0]));
    printf("%s",ipbuf);
```

**inet_aton**
下記も一応値が返ってくる

```c
    struct in_addr addr1;
    struct in_addr addr2;
    
    str = "173.194.120.66";//google.com
    inet_aton(str, &addr1);
    printf("inet_aton --------- %s = %x\n", str, addr1.s_addr);
```

上記どっちも[Appleの公式](https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW11)には非推奨と書いてあるけど、一応動く
値は16進数文字列みたいのが返ってくるのでよく分からなかったけど、実行時点でエラーになるわけではなくその関数使ってIPv4リテラルを使った時にconnectしようとすると繋がらない、みたいになると思います



#WebRTCのSTUNに関する挙動
もともとWebRTCxSTUNが繋がらない理由を調べていたので、これも載せておきます
STUNはざっくり言うと外部のサーバーにリクエストすると自分のグローバルIPとポート返してくれるプロトコルです

##IPv6ポイントでも正常動作するSTUNクライアント
Objective-C STUNでググって出てきたSTUNクライアント
https://github.com/soulfly/STUN-iOS

上記でrfc5766-turn-serverで立てたSTUNサーバーにIPv6ポイントからアクセス
→正常にIPv4アドレスが戻ってくる

[ソース](https://github.com/soulfly/STUN-iOS/blob/master/STUN/STUN/GCDAsyncUdpSocket.m)を見るとGCDAsyncUdpSocket.mの1186行目あたりでgetaddrinfoで接続先HOSTを取得している。
[Supporting IPv6 DNS64/NAT64 Networks](https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW11)にもあった通り、**getaddrinfo**なら問題ない

##IPv6ポイントでは失敗するSTUNクライアント
非常に申し訳ないですが、古いコードの例として下記を挙げさせて頂きます
https://github.com/gregnietsky/stun-c

これをXcodeにそのままコピーして、Objective-Cから呼び出して実行したところIPv6ポイントでは失敗しました。
[ソース](https://github.com/gregnietsky/stun-c/blob/master/stun.c)のmain関数(365行目以降)でconnect処理をしていて、AF_INET定数を使ってinet_addrで接続しています。
[Supporting IPv6 DNS64/NAT64 Networks](https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW11)の非推奨APIでは動かない例になります。


#まとめ
NSURLSessionやCFNetwork等、Objective-Cレイヤーの通信APIはApple側で対応しているので、あまり気にしなくていい
C言語のDNS系関数はIPv4とIPv6のデュアルスタックで動くようになってないと今後iOSアプリで使えなくなる
Cやネットワーク周りが良くわかっていないので、間違っている点等あればご指摘頂けるとありがたいです