iOS Программа Resolve DNS иногда возвращает неверные IP-адреса - PullRequest
0 голосов
/ 18 июня 2020

Привет,

Я работаю над приложением iOS, которое требует программного разрешения DNS .

Считайте это прокси-сервером для разрешения всех запросов DNS на iPhone. Я получаю DNS-запросы от каждого приложения на iPhone и отправляю обратно соответствующий список IPList

. Я пробовал несколько методов, но оба имеют одинаковые ответы. Тот, который я решил использовать, приведен ниже: resolveHost функция, написанная в objective- c и c Я вызываю этот метод из быстрого кода.

Вот как я звоню из swift, также использующий образец хоста / URL, значением хоста может быть любой домен ("google.com, apple.com et c") или домен / хост в результате следов при открытии сайта в mkwebview

let host = "www.opera.com"

let ipArray = ResolveUtil (). ResolveHost (host, usingDNSServer: «8.8.8.8») as! [String]

Точнее Приложение Facebook не работает с IP-адресами, возвращаемыми из функции resolveHost

Под «не работает» я имею в виду, что приложение не подключается к IP-адресам возвращается из функций

Иногда он возвращает 192.16.192.16 как часть других IP-адресов для некоторых хостов / доменов. Что это за IP?

- (NSArray*)resolveHost:(NSString *)host usingDNSServer:(NSString *)dnsServer
{

    NSMutableArray* result = [[NSMutableArray alloc] init];
    struct __res_state res;
    setup_dns_server(&res, [dnsServer cStringUsingEncoding:NSASCIIStringEncoding]);
    int count;
    char** ips = query_ips(&res, [host cStringUsingEncoding:NSUTF8StringEncoding], &count);
    for (int i=0; i<count; i++){
        [result addObject:[[NSString alloc] initWithCString:ips[i] encoding:NSASCIIStringEncoding]];
    }

    for (int i=0; i<count; i++){

        free(ips[i]);
    }
    free(ips);
    ips = NULL;

    return result;

}

char ** query_ips(res_state res, const char *host, int* count)
{
    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);

    int messageCount = ns_msg_count(handle, ns_s_an);
    *count = messageCount;
    char **ips = malloc(messageCount * sizeof(char *));

    for (int i=0; i < messageCount; i++) {
        ips[i] = malloc(16 * sizeof(char));
        memset(ips[i], '\0', sizeof(16));
        ns_rr rr;
        if(ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
            strcpy(ips[i], inet_ntoa(*(struct in_addr *)ns_rr_rdata(rr)));
        }
    }
    return ips;
}

Другой метод

func resolveIp(_ hostUrl:String) -> [String]{
        var ips:[String] = [String]()
        let host = CFHostCreateWithName(nil,hostUrl as CFString).takeRetainedValue()
        CFHostStartInfoResolution(host, .addresses, nil)
        var success: DarwinBoolean = false
        if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray? {
            for case let theAddress as NSData in addresses {
                var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
                               &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
                    let numAddress = String(cString: hostname)
                    ips.append(numAddress)
                }
            }
        }
        Logger.info("\(#function) validIPs:\(ips.joined(separator: "-")) url:\(hostUrl)")
        return ips
    }

Ответы [ 2 ]

0 голосов
/ 20 июня 2020

Возможно, я не объяснил формулировку проблемы в моем первоначальном вопросе, но мне удалось исправить ошибку, поэтому я подумал, что должен написать здесь свои выводы. Мое приложение работает как DNS-прокси, поэтому его основная задача заключалась в разрешении доменов и возвращении IP-адресов.

Я использовал функцию resolveHost для разрешения IP. Эта функция имеет все проблемы, упомянутые zrzka , поэтому, если кто-то хочет использовать, пожалуйста, примите во внимание его моменты.

Проблема, с которой я столкнулся, заключалась в том, что функция возвращает несколько IP-адресов против указанных c хосты / домены, которые не кажутся действительными, я говорю недействительными, потому что это не были IP-адреса, которые можно было проверить, и из Wireshark я подтвердил, что соединение на этих IP-адресах было неудачным, даже если возвращенный IPList содержит действительный IP-адрес по некоторому индексу, он все еще вызывает ненужную задержку из-за первого попробуйте использовать недопустимые IP-адреса, поскольку они находятся перед действительными IP-адресами в списке.

В ходе дальнейшего расследования я узнал, что эти недопустимые IP-адреса относятся к типу ответа CNAME, который отображает псевдоним в записи DNS, я не знаю, что я все равно должен называть их недействительными или нет, но их игнорирование помогло мне. Теперь я принимаю только ответы типа A или AAAA из ответа DNS. Я добился этого с помощью простой проверки в следующей функции.

char ** query_ips(res_state res, const char *host, int* count)
{
    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);

    int messageCount = ns_msg_count(handle, ns_s_an);
    *count = messageCount;
    char **ips = malloc(messageCount * sizeof(char *));

    for (int i=0; i < messageCount; i++) {
        ips[i] = malloc(16 * sizeof(char));
        memset(ips[i], '\0', sizeof(16));
        ns_rr rr;
        if(ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
            if (1 == rr.type || 28 == rr.type) // here is the new check
              strcpy(ips[i], inet_ntoa(*(struct in_addr *)ns_rr_rdata(rr)));
        }
    }
    return ips;
}
0 голосов
/ 18 июня 2020

192.16.192.16

Что это за IP? Совершенно действующий IPv4. Он возвращается к basento.nikhef.nl.

Почему он возвращается?

Я не знаю. Возможно, см. resolv.h:

 * Mac OS supports a DNS query routing API (see <dns.h>) which is used by
 * most system services to access DNS.  The BIND-9 APIs described here are
 * a lower-level that does not do query routing or search amongst multiple
 * resolver clients.  The results of DNS queries from this API may differ
 * significantly from the results of queries sent to the <dns.h> API.  We
 * strongly encourage developers to use higher-level APIs where possible.

Под «неработающим» я подразумеваю, что приложение не подключается к IP-адресам, возвращаемым функциями.

Это не имеет никакого отношения с разрешением имени / ip адреса.

Проблема может быть в другом месте. Ваш провайдер может заблокировать его, на IP-адресе не запущена служба, вам не разрешен доступ к нему ... По многим причинам.

В частности, приложение Facebook не работает с возвращаемыми IP-адресами из функции resolveHost.

Для меня это вообще не имеет смысла. У вас есть собственное приложение, вы разрешаете в нем IP-адреса, а затем говорите, что оно не работает с Facebook. Честно говоря, я понятия не имею, что вы имеете в виду.


Почему я отвечаю на этот вопрос? Что ж, вы не должны слепо копировать и вставлять код из других вопросов о переполнении стека или любых других сайтов. Провел исследование, и оно похоже на копирование и вставку некоторых других ответов.

Почему? Код в вашем вопросе не обрабатывает ошибки, не соответствует документации ... Это чистая удача, что он работает для вас.

Что, если это ваша проблема? Вы когда-нибудь рассматривали этот вариант?

Вот пример Resolver, который вы можете использовать / test с вашими условиями. Это может решить ваши проблемы, а может и не решить.

#import <resolv.h>
@import Darwin.POSIX.arpa;

@interface Resolver: NSObject

- (nullable instancetype)initWithDNSServer:(nonnull NSString *)server;
- (nullable NSArray<NSString *> *)resolveHost:(nonnull NSString *)host;

@end

@implementation Resolver {
    struct __res_state *state;
}

- (void)dealloc {
    if (state != NULL) {
        // man 3 resolver:
        //
        // res_ndestroy() should be call to free memory allocated by res_ninit() after last use.
        if ((state->options & RES_INIT) == RES_INIT) {
            res_ndestroy(state);
        }
        free(state);
        state = NULL;
    }
}

- (nullable instancetype)initWithDNSServer:(nonnull NSString *)server {
    if ((self = [super init]) == nil) {
        return nil;
    }

    // man 3 resolver:
    //
    // The memory referred to by statp must be set to all zeros prior
    // to the first call to res_ninit(). res_ndestroy() should be call to free memory
    // allocated by res_ninit() after last use.
    if ((state = calloc(1, sizeof(*state))) == NULL) {
        return nil;
    }

    // 0 success
    if (res_ninit(state) != 0) {
        return nil;
    }

    // Avoid calling inet_aton later with NULL if we can't convert it to ASCII
    if (![server canBeConvertedToEncoding:NSASCIIStringEncoding]) {
        return nil;
    }

    struct in_addr addr;

    // man 3 inet_aton:
    //
    // It returns 1 if the string was successfully interpreted ...
    if (inet_aton([server cStringUsingEncoding:NSASCIIStringEncoding], &addr) != 1) {
        return nil;
    }

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

    return self;
}

- (nullable NSArray<NSString *> *)resolveHost:(nonnull NSString *)host {
    // Avoid calling res_nquery with NULL
    if (![host canBeConvertedToEncoding:NSASCIIStringEncoding]) {
        return nil;
    }

    u_char answer[NS_PACKETSZ];

    int len = res_nquery(state, [host cStringUsingEncoding:NSASCIIStringEncoding],
                         ns_c_in, ns_t_a, answer, sizeof(answer));

    // -1 = error
    if (len == -1) {
        return nil;
    }

    ns_msg handle;

    // 0 success, -1 error
    if (ns_initparse(answer, len, &handle) != 0) {
        return nil;
    }

    u_int16_t count = ns_msg_count(handle, ns_s_an);
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0 ; i < count ; i++) {
        ns_rr rr;
        // 0 success, -1 error
        if (ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
            char *address = inet_ntoa(*(struct in_addr *)ns_rr_rdata(rr));

            if (address == NULL) {
                continue;
            }

            NSString *ip = [NSString stringWithCString:address
                                              encoding:NSASCIIStringEncoding];
            [result addObject:ip];
        }
    }

    return result;
}

@end

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

Resolver *resolver = [[Resolver alloc] initWithDNSServer:@"8.8.8.8"];
NSLog(@"%@", [resolver resolveHost:@"www.opera.com"]);

Вывод:

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