CFHostGetAddressing does not return IPv6 addresses

Code snippet below:

  NSString *host = @"time.google.com";
  CFHostRef cfHostRef = CFHostCreateWithName(nil, (__bridge CFStringRef) host);
  Boolean didLookup = CFHostStartInfoResolution(cfHostRef, kCFHostAddresses, nil);
  NSLog(@"didLookup=%d", didLookup);
  CFArrayRef addresses = CFHostGetAddressing(cfHostRef, &didLookup);
  struct sockaddr *remoteAddr;
  long count = CFArrayGetCount(addresses);
  NSLog(@"count=%ld (this should include both ip4 and ip6)", count);
  for(int i = 0; i < count; i++) {
    CFDataRef saData = (CFDataRef)CFArrayGetValueAtIndex(addresses, i);
    remoteAddr = (struct sockaddr*)CFDataGetBytePtr(saData);
    NSLog(@"family=%d (AF_INET=%d, AF_INET6=%d)",remoteAddr->sa_family, AF_INET, AF_INET6);
    NSString* addrPretty = nil;
    switch (remoteAddr->sa_family) {
      case AF_INET: {
        char dest[INET_ADDRSTRLEN];
        struct sockaddr_in *ip4 = (struct sockaddr_in *) remoteAddr;
        addrPretty = [NSString stringWithFormat: @"%s", inet_ntop(AF_INET, &ip4->sin_addr, dest, INET_ADDRSTRLEN)];
        break;
      }
      case AF_INET6: {
        char dest[INET6_ADDRSTRLEN];
        struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *) remoteAddr;
        addrPretty = [NSString stringWithFormat: @"%s", inet_ntop(AF_INET6, &ip6->sin6_addr, dest, INET6_ADDRSTRLEN)];
        break;
      }
      default:
        break;
    }
    NSLog(@"addrPretty=%@", addrPretty);
  }

As far as I understand this should print out both IPv4 and IPv6 addresses, but it only does the former. This is as tested on both a simulator and a real device, on different networks.

Note that I can traceroute6 -I time.google.com and see IPv6 addresses just fine, and I can also do set q=AAAA in the nslookup prompt and get the expected addresses when performing the query for time.google.com in the same prompt.

Post not yet marked as solved Up vote post of jantonio Down vote post of jantonio
366 views

Replies

Does your device have IPv6 connectivity to the wider Internet?

CFHost will only return results that you can feasibly connect to. Unless your device has IPv6 connectivity, you can’t connect to this host’s IPv6 address and thus CFHost won’t return it. You’ll see this behaviour for all APIs that work through the system resolver.

If you pass CFHost an address where IPv6 connectivity is feasible, it’ll return the IPv6 address. A good way to test this is with a local. address. For example:

let h = CFHostCreateWithName(nil, "fluffy.local." as NSString).takeRetainedValue()
let ok = CFHostStartInfoResolution(h, .addresses, nil)
assert(ok)
let addresses = (CFHostGetAddressing(h, nil)?.takeUnretainedValue() as NSArray? ?? []) as! [Data]
for a in addresses {
    print((a as NSData).debugDescription)
}
// prints:
// <1c1e0000 00000000 fe800000 00000000 aa2066ff fe2e49ca 0f000000>
// <10020000 c0a80127 00000000 00000000>

I can also do set q=AAAA in the nslookup prompt and get the expected addresses

Right. That’s because nslookup (and dig) have their own resolver.

IMPORTANT Implementing your own resolver makes sense for these DNS debugging tools but it’s a bad idea in general.

CFHost is on the path to deprecation and, even before then, was only the right option in very obscure circumstances. If you can explain more about your big picture, I should be able to guide you towards a better long-term path.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi, thanks!

Does your device have IPv6 connectivity to the wider Internet?

That's a very good question. In all honesty I'm not too familiar with either iOS or networking, and given your point about the nslookup stack I'm going to go ahead and assume I probably don't have IPv6 connectivity no (your test code fails on the assertion for me, but then again I probably just don't know how to run a Swift app correctly). Thanks for clearing that out.

That said, my use case is that I need to build an SNTP client with objective C as a hard requirement, and I need to offer an API that allows filtering addresses resolved from the chosen servers based on family. If the CFHost APIs are going to be deprecated, what would be the way to go?