iOS: как указать DNS для преобразования имени хоста в IP-адрес? - PullRequest
0 голосов
/ 05 июня 2018

Как видно из названия, у меня есть имя хоста (например, www.example.com), которое я хочу разрешить, используя указанный DNS-сервер.Например, в одном случае я хочу использовать Google IPv4 DNS, а в другом случае Google IPv6 DNS.

Я просмотрел SO на что-то подобное на iOS и нашел такие вопросы ( Swift - GetIP-адрес устройства ), поэтому я уверен, что это можно сделать, но мне неясно, как?

Как я могу это сделать?

РЕДАКТИРОВАТЬ 06/07/2018

@ mdeora предлагаемое решение от http://www.software7.com/blog/programmatically-query-specific-dns-servers-on-ios/

Это решение работает, но только если я использую IPv4 DNS, например, Google 8.8.8.8.Если я пытаюсь использовать IPv6 DNS 2001: 4860: 4860 :: 8888, я ничего не получаю.

Мне удалось изменить конверсию:

void setup_dns_server(res_state res, const char *dns_server)
{
    res_ninit(res);
    struct in_addr addr;

//    int returnValue = inet_aton(dns_server, &addr);
    inet_pton(AF_INET6, dns_server, &addr); // for IPv6 conversion

    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;

};

Но все еще возникают проблемы с этим:

void query_ip(res_state res, const char *host, char ip[])
{
    u_char answer[NS_PACKETSZ];//NS_IN6ADDRSZ 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)));
        }
    }
}

Я получаю -1 за лен.Судя по тому, что я понял, мне нужно настроить res_state для IPv6.

Ответы [ 3 ]

0 голосов
/ 07 июня 2018

Ниже приведен пересмотренный код для настройки DNS -

void setup_dns_server(res_state res, const char *dns_server)
    {
        res_ninit(res);
        struct in_addr6 addr;

    //    int returnValue = inet_aton(dns_server, &addr);
        inet_pton(AF_INET6, dns_server, &addr); // for IPv6 conversion

        res->nsaddr_list[0].sin_addr = addr;
        res->nsaddr_list[0].sin_family = AF_INET6;
        res->nsaddr_list[0].sin_port = htons(NS_DEFAULTPORT);
        res->nscount = 1;

    };

И код запроса -

void query_ip(res_state res, const char *host, char ip[])
{
    u_char answer[NS_PACKETSZ];//NS_IN6ADDRSZ 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_addr6 *)ns_rr_rdata(rr)));
        }
    }
}

PS - я не смог проверить его, но он долженработа для ipv6 днс.

0 голосов
/ 13 июня 2018

Здесь код из моего поста, который уже был упомянут выше, просто немного адаптирован для использования IPv6.

Адаптируйте setup_dns_server

Сначала мы можем начать с измененийв setup_dns_server:

void setup_dns_server(res_state res, const char *dns_server) {
    struct in6_addr addr;

    inet_pton(AF_INET6, dns_server, &addr);

    res->_u._ext.ext->nsaddrs[0].sin6.sin6_addr = addr;
    res->_u._ext.ext->nsaddrs[0].sin6.sin6_family = AF_INET6;
    res->_u._ext.ext->nsaddrs[0].sin6.sin6_port = htons(NS_DEFAULTPORT);
    res->nscount = 1;
}

Добавить __res_state_ext

Это не скомпилируется из-за отсутствия структуры __res_state_ext.К сожалению, эта структура находится в частном заголовочном файле.

Но определение этого можно взять отсюда: https://opensource.apple.com/source/libresolv/libresolv-65/res_private.h.auto.html:

struct __res_state_ext {
    union res_sockaddr_union nsaddrs[MAXNS];
    struct sort_list {
        int af;
        union {
            struct in_addr  ina;
            struct in6_addr in6a;
        } addr, mask;
    } sort_list[MAXRESOLVSORT];
    char nsuffix[64];
    char bsuffix[64];
    char nsuffix2[64];
};

Структура может быть добавлена, например:вверху файла.

Адаптировать resolHost

Изменения включают более длинный буфер для ip (INET6_ADDRSTRLEN).res_ninit перемещен из setup_dns_server в этот метод и теперь сопоставляется с res_ndestroy.

+ (NSString *)resolveHost:(NSString *)host usingDNSServer:(NSString *)dnsServer {
    struct __res_state res;
    char ip[INET6_ADDRSTRLEN];
    memset(ip, '\0', sizeof(ip));

    res_ninit(&res);
    setup_dns_server(&res, [dnsServer cStringUsingEncoding:NSASCIIStringEncoding]);
    query_ip(&res, [host cStringUsingEncoding:NSUTF8StringEncoding], ip);
    res_ndestroy(&res);

    return [[NSString alloc] initWithCString:ip encoding:NSASCIIStringEncoding];
}

Извлечение адресов IPv6

Изменения выше уже достаточны, если вы просто хотитеиспользуйте IPv6-адрес для вашего DNS-сервера.Таким образом, в query_ip нет необходимости вносить изменения, если вы все еще хотите получить адреса IPv4.

Если вы хотите получить IPv6-адреса также с DNS-сервера, вы можете сделать это:

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_aaaa, 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) {
            inet_ntop(AF_INET6, ns_rr_rdata(rr), ip, INET6_ADDRSTRLEN);
        }
    }
}

Обратите внимание: мы используем здесь ns_t_aaaa для получения записей ресурсов AAAA (quad-Запись), потому что в DNS это указывает на соответствие между адресом IPv6 и именем хоста.Для многих хостов такой записи quad-A нет, то есть вы можете просто связаться с ними через IPv4.

Call

Вы можете назвать это, например, так:

NSString *resolved = [ResolveUtil resolveHost:@"www.google.com" usingDNSServer:@"2001:4860:4860::8888"];
NSLog(@"%@", resolved);

Результат будет выглядеть следующим образом:

test output

Отказ от ответственности

Это просто простые примеры вызовов, которые демонстрируют основное использование функций.Там нет обработки ошибок.

0 голосов
/ 06 июня 2018

Вы можете сделать это, используя приведенный ниже код swift -

import Foundation
let task = Process()
task.launchPath = "/usr/bin/env"
task.arguments = ["dig", "@8.8.8.8", "google.com"]

let pipe = Pipe()
task.standardOutput = pipe
task.launch()

let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)

print(output!)

. В приведенном выше коде используйте DNS-сервер по вашему выбору, заменив 8.8.8.8

Для Objective-C iOS см. Нижессылка - https://www.software7.com/blog/programmatically-query-specific-dns-servers-on-ios/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...