In general, to obtain the local DNS address, we use the following method.

Add the libresolv. TBD library to your system. We then introduce the following header files into the header file:

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <resolv.h>
#include <dns.h>
Copy the code

Then use, or adapt, the following code:

NSMutableArray *DNSList = [NSMutableArray array];
res_state res = malloc(sizeof(struct __res_state));
int result = res_ninit(res);
if (result == 0) {
    for (int i=0; i < res->nscount; i++) { NSString *s = [NSString stringWithUTF8String:inet_ntoa(res->nsaddr_list[i].sin_addr)]; [DNSList addObject:s]; }}res_nclose(res);
free(res);
// dnsList is the DNS server address
Copy the code

Unfortunately, a friend of mine told me that using this code would cause a memory leak. I tried it out for myself, and it did. What’s wrong with it?

Lookup process

Int result = res_ninit(res); The memory created by this code has not been freed.

But I’ve already written res_nclose(res); Ah.

I had no choice but to click on the res_ninit page and search them one by one.

Finally, after a long search, I found an Oracle document.

There were a few notes in it that I found fascinating:

  1. The res_ndestroy() function should be called to free memory allocated by res_ninit() after the last use of statp.

  2. The res_nclose() function closes any open files referenced through statp.

  3. The res_ndestroy() function calls res_nclose(), then frees any memory allocated by res_ninit() referenced through statp.

And this sample code:

#include <resolv.h>
#include <string.h>

int main(int argc, char **argv)
{
    int len;
    struct __res_state statp;
    union msg {
        uchar_t buf[NS_MAXMSG];
        HEADER  h;
    } resbuf;

    /* Initialize resolver */
    memset(&statp, 0.sizeof(statp));
    if (res_ninit(&statp) < 0) {
        fprintf(stderr, "Can't initialize statp.\n");
        return (1);
    }

    /* * Turning on DEBUG mode keeps this example simple, * without need to output anything. */
    statp.options |= RES_DEBUG;

    /* Search for A type records */
    len = res_nsearch(&statp, "example.com", C_IN, T_A,
         resbuf.buf, NS_MAXMSG);
    if (len < 0) {
        fprintf(stderr, "Error occured during search.\n");
        return (1);
    }
    if (len > NS_MAXMSG) {
        fprintf(stderr, "The buffer is too small.\n");
        return (1);
    }

    / *... Process the received answer ... * /

    /* Cleanup */
    res_ndestroy(&statp);
    return (0);
}
Copy the code

This means:

  • DNS information is stored in a STATP, which is created using res_ninit and then read from the crowd.
  • The res_nclose function closes all open statp files, but does not free the memory. If you want to free memory while closing, you should use the res_ndestroy function.

The correct code

NSMutableArray *DNSList = [NSMutableArray array];
res_state res = malloc(sizeof(struct __res_state));
int result = res_ninit(res);
if (result == 0) {
    for (int i=0; i < res->nscount; i++) { NSString *s = [NSString stringWithUTF8String:inet_ntoa(res->nsaddr_list[i].sin_addr)]; [DNSList addObject:s]; }}res_ndestroy(res);
free(res);
// dnsList is the DNS server address
Copy the code

reference

man pages section 3: Networking Library Functions