Resolving DNS Hostnames

This article explains how to resolve a DNS hostname in a way that offers you maximum flexibility.

There are three primary APIs in OS X and iOS for resolving hostnames: NSHost (only in OS X), CFHost, and the POSIX resolver API.

Resolving Hostnames with CFHost

To resolve a host with CFHost:

  1. Create a CFHostRef object by calling CFHostCreateWithName.

  2. Call CFHostSetClient and provide the context object of your choice and a callback function that will be called when resolution completes.

  3. Call CFHostScheduleWithRunLoop to schedule the resolver on your run loop.

  4. Call CFHostStartInfoResolution to tell the resolver to start resolving, passing kCFHostAddresses as the second parameter to indicate that you want it to return IP addresses.

  5. Wait for the resolver to call your callback. Within your callback, obtain the results by calling CFHostGetAddressing. This function returns an array of CFDataRef objects, each of which contains a POSIX sockaddr structure.

The process for reverse name resolution (translating an IP address into a hostname) is similar, except that you call CFHostCreateWithAddress to create the object, pass kCFHostNames to CFHostStartInfoResolution, and call CFHostGetNames to retrieve the results.

Resolving Hostnames with POSIX Calls

If you intend to use POSIX calls to resolve hostnames, be aware that these calls are synchronous and should not be used on the main thread in a GUI app. Instead, you should either create a separate POSIX thread or a GCD task and perform these calls within that context.

POSIX defines three functions in <netdb.h> for resolving hostnames:

getaddrinfo

Returns all the resolved addresses for a given hostname. This function is the preferred way to obtain address information at the POSIX level. You can find sample code in its man page (linked above).

Important: Some older DNS servers do not reply to IPv6 lookup requests with an error. The POSIX getaddrinfo function attempts to hide this misbehavior by canceling outstanding IPv6 queries shortly after receiving a successful IPv4 reply. If your app would benefit from continuing to receive IPv6 addresses until you connect successfully (rather than stopping as soon as you have an IPv4 address that might or might not work), then you should use an asynchronous API such as CFHost.

gethostbyname

Returns a single IPv4 address for a given hostname. This function is discouraged for new development because it is limited to IPv4 addresses.

gethostbyname2

Returns a single address for a given hostname in the specified address family (AF_INET, AF_INET6, and so on).

Although this function allows you to get around the IPv4 limitations of gethostbyname, it still limits your ability to try multiple addresses at once and choose the fastest one. Thus, this function is primarily intended as a nearly drop-in replacement for gethostbyname in existing code. The getaddrinfo is preferred for use in new code.

For reverse name resolution (translating an IP address into a hostname), POSIX provides getnameinfo and gethostbyaddr. The getnameinfo function is preferred because it is more flexible.

To learn more about these functions, read their respective man pages, linked above.