Hello,
I am in the process of trying to make an application work correctly in an IPv6 only environment on iOS as required for App Store certification. It works by sending a request to some service which returns an IP address to establish a UDP connection with. Currently, this returns an IPv4 address to connect to (via a low level socket), and it's a large amount of work to get this to support IPv6 correctly.
For the time being, I am trying to use getaddrinfo to synthesize an IPv6 address using the code example provided in https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW23
however, it just returns the IPv4 address - rather than the synthesized IPv6 address - when running on an iPhone XS (running iOS 12.1.4) with no sim card, connected via WiFi to a MacBook Pro wifi hotspot (running macOS 10.14.3) with the NAT64 proxy enabled.
Looking at the wifi information on the iPhone itself, it currently has a link-local IPv4 address (169.254.0.0/24) and 2 IPv6 addresses (starting 2001:2::aab1:...), so I believe the setup is correct.
I created an Xcode iOS project with the following code in main.mm:
#import
#import "AppDelegate.h"
#include
#include
#include
#include
#include
void test_getaddrinfo(int family) {
uint8_t ipv4[4] = {192, 0, 2, 1};
struct addrinfo hints, *res, *res0;
int error;
char ipv4_str_buf[INET_ADDRSTRLEN] = { 0 };
const char *ipv4_str = inet_ntop(AF_INET, &ipv4, ipv4_str_buf, sizeof(ipv4_str_buf));
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_DEFAULT;
error = getaddrinfo(ipv4_str, "http", &hints, &res0);
if (error) {
printf("%s", gai_strerror(error));
}
for (res = res0; res; res = res->ai_next) {
printf("ai_flags:%d ai_family:%d ai_socktype:%d ai_protocol:%d ai_addrlen:%d ai_canonname:%s\n",
res->ai_flags, res->ai_family, res->ai_socktype, res->ai_protocol, res->ai_addrlen,
res->ai_canonname == NULL ? "" : res->ai_canonname);
char* s = NULL;
switch (res->ai_addr->sa_family) {
case AF_INET: {
struct sockaddr_in* addr_in = (struct sockaddr_in*)res->ai_addr;
s = (char*)malloc(INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(addr_in->sin_addr), s, INET_ADDRSTRLEN);
break;
}
case AF_INET6: {
struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)res->ai_addr;
s = (char*)malloc(INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
break;
}
default:
break;
}
printf("IP address: %s\n", s);
free(s);
}
freeaddrinfo(res0);
}
int main(int argc, char * argv[]) {
printf("--unspec--\n");
test_getaddrinfo(PF_UNSPEC);
printf("--inet6--\n");
test_getaddrinfo(PF_INET6);
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
and this gives me the following output:
--unspec--
ai_flags:0 ai_family:2 ai_socktype:1 ai_protocol:6 ai_addrlen:16 ai_canonname:
IP address: 192.0.2.1
--inet6--
ai_flags:0 ai_family:30 ai_socktype:1 ai_protocol:6 ai_addrlen:28 ai_canonname:
IP address: ::ffff:192.0.2.1
when I would expect this to print "64:ff9b::192.0.2.1" in both PF_UNSPEC and PF_INET6 cases, as specified both in the Apple Developer documentation and the manpage for getaddrinfo.
Can anybody advise as to what I may have done wrong during setup, or is this a regression in either macOS or iOS?
Thanks in advance.