Programmatically Query Specific DNS Servers on iOS
Remarks
When I decided to relaunch my blog, I initially removed all the old posts from the server assuming that they were no longer being viewed. However, checking the server logs revealed ongoing access attempts for two specific blog posts from about ten years ago.
Given this unexpected interest, I decided to republish these posts to make them available again. One post is about quering specific DNS servers, which was originally published on January 23, 2015.
The original code was limited to IPv4 DNS queries, as was noted in a 2018 Stackoverflow discussion. In response, I provided an updated answer on Stackoverflow that extended the code for IPv6 support. If you’re interested an IPv6 solution, just see my Stackoverflow answer regarding IPv6.
Below is the original article without any changes. Maybe they’re still useful for someone out there!
Original Article
DNS servers handle the mapping of hostnames to IP addresses. This happens under the hood automatically, unless you want to access some non-public resources that are managed by a non-public DNS server.
In my use case this was needed during the early phase of the development of an iOS app. So all team members had access to test resources without the need to change local network settings.
JetBrains has with CLion a new C/C++ IDE in development, publicly available through their Early Access Program. So the small routines were a good opportunity for me to get a first impression of their new tool. Jetbrains would not be themselves without offering comfortable editing and refactoring features – refactoring of C code, nice!
So here is a screencast of creating the small routines in CLion and integrating them into an iOS app in Xcode.
The header file:
#import <Foundation/Foundation.h>
@interface ResolveUtil : NSObject
+ (NSString *)resolveHost:(NSString *)host usingDNSServer:(NSString *)dnsServer;
@end
The implementation file:
#include <resolv.h>
#include <arpa/inet.h>
#include <string.h>
#import "ResolveUtil.h"
void setup_dns_server(res_state res, const char *dns_server);
void query_ip(res_state res, const char *host, char ip[]);
@implementation ResolveUtil
+ (NSString *)resolveHost:(NSString *)host usingDNSServer:(NSString *)dnsServer
{
struct __res_state res;
char ip[16];
memset(ip, '\0', sizeof(ip));
setup_dns_server(&res, [dnsServer cStringUsingEncoding:NSASCIIStringEncoding]);
query_ip(&res, [host cStringUsingEncoding:NSUTF8StringEncoding], ip);
return [[NSString alloc] initWithCString:ip encoding:NSASCIIStringEncoding];
}
void query_ip(res_state res, const char *host, char ip[])
{
u_char answer[NS_PACKETSZ];
int len = res_nquery(res, host, ns_c_in, ns_t_a, answer, sizeof(answer));
ns_msg handle;
ns_initparse(answer, len, &handle);
if(ns_msg_count(handle, ns_s_an) > 0) {
ns_rr rr;
if(ns_parserr(&handle, ns_s_an, 0, &rr) == 0) {
strcpy(ip, inet_ntoa(*(struct in_addr *)ns_rr_rdata(rr)));
}
}
}
void setup_dns_server(res_state res, const char *dns_server)
{
res_ninit(res);
struct in_addr addr;
inet_aton(dns_server, &addr);
res->nsaddr_list[0].sin_addr = addr;
res->nsaddr_list[0].sin_family = AF_INET;
res->nsaddr_list[0].sin_port = htons(NS_DEFAULTPORT);
res->nscount = 1;
}
@end