Software7

Personal Developer Notebook

Programmatically query specific DNS servers on iOS

 

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