我一直在寻找一种方法来查询DNS以在iOS中找到NAPTR时遇到很多麻烦。似乎有许多相对简单的方法可以解析为IP,但是我特别需要在DNS查找中找到所有NAPTR记录。我宁愿这样做,而不必尽可能引入任何外部库。如果有人能够做到这一点(或可以从中推断出类似的东西),我将不胜感激。

所有代码必须在iOS 5.0+中运行

最佳答案

我最终使用了DNSServiceQueryRecord。

            DNSServiceRef sdRef;
            DNSServiceQueryRecord(&sdRef, 0, 0,
                                  "google.com",
                                  kDNSServiceType_NAPTR,
                                  kDNSServiceClass_IN,
                                  callback,
                                  NULL);

            DNSServiceProcessResult(sdRef);
            DNSServiceRefDeallocate(sdRef);

在实际使用中,我发现存在一个问题,如果没有结果,应用程序将无限期挂起,因此最终不得不调整代码以在结果上添加超时。
/*
 Attempt to fetch the NAPTR from the stored server address.  Since iOS will continue waiting
 until told directly to stop (even if there is no result) we must set our own timeout on the
 request (set to 5 seconds).
 On success, the callback function is called.  On timeout, the kSRVLookupComplete notification
 is sent.
 */
- (void)attemptNAPTRFetch {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        DNSServiceRef sdRef;
        DNSServiceErrorType err;

        err = DNSServiceQueryRecord(&sdRef, 0, 0,
                                       [server cStringUsingEncoding:[NSString defaultCStringEncoding]],
                                       kDNSServiceType_NAPTR,
                                       kDNSServiceClass_IN,
                                       callback,
                                       NULL);

        // This stuff is necessary so we don't hang forever if there are no results
        int dns_sd_fd = DNSServiceRefSockFD(sdRef);
        int nfds = dns_sd_fd + 1;
        fd_set readfds;
        struct timeval tv;
        int result;

        int stopNow = 0;
        int timeOut = 5; // Timeout in seconds

        while (!stopNow) {
           FD_ZERO(&readfds);
           FD_SET(dns_sd_fd, &readfds);
           tv.tv_sec = timeOut;
           tv.tv_usec = 0;

           result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
           if (result > 0) {
               if(FD_ISSET(dns_sd_fd, &readfds)) {
                   err = DNSServiceProcessResult(sdRef);
                   if (err != kDNSServiceErr_NoError){
                       NSLog(@"There was an error");
                   }
                   stopNow = 1;
               }
           }
           else {
               printf("select() returned %d errno %d %s\n", result, errno, strerror(errno));
               if (errno != EINTR) {
                   stopNow = 1;
                   postNotification(kSRVLookupComplete, nil);
               }
           }
        }

        DNSServiceRefDeallocate(sdRef);
   });
}

然后,对于回调:
static void callback(DNSServiceRef sdRef,
          DNSServiceFlags flags,
          uint32_t interfaceIndex,
          DNSServiceErrorType errorCode,
          const char *fullname,
          uint16_t rrtype,
          uint16_t rrclass,
          uint16_t rdlen,
          const void *rdata,
          uint32_t ttl,
          void *context)
{
    uint16_t order, pref;
    char flag;
    NSMutableString *service = [[NSMutableString alloc] init];
    NSMutableString *replacement = [[NSMutableString alloc] init];

    const char *data = (const char*)rdata;

    order = data[1];
    pref = data[3];
    flag = data[5];
    int i = 7;
    while (data[i] != 0){
        [service appendString:[NSString stringWithFormat:@"%c", data[i]]];
        i++;
    }
    i += 2;
    while(data[i] != 0){
        if(data[i] >= 32 && data[i] <= 127)
            [replacement appendString:[NSString stringWithFormat:@"%c", data[i]]];
        else
            [replacement appendString:@"."];
        i++;
    }
    NSLog(@"\nOrder: %i\nPreference: %i\nFlag: %c\nService: %@\nReplacement: %@\n", order, pref, flag, service, replacement);
}

这似乎对我有用。当然,您将使用回调中的所有已解析数据来执行任何其他必要的工作,或者将数据存储在以后使用的位置。

09-11 02:47