【问题标题】:getaddrinfo(): how to distinguish between resolution failure and non-resolvable hostname?getaddrinfo():如何区分解析失败和不可解析的主机名?
【发布时间】:2014-09-11 09:38:40
【问题描述】:

理论上,getaddrinfo(3) 的返回值应该允许区分无法解析的主机名和 DNS 服务器的问题:

RETURN VALUE
       getaddrinfo()  returns  0  if  it  succeeds,  or  one of the following
       nonzero error codes:

       EAI_ADDRFAMILY
              The specified network host does not have any network  addresses
              in the requested address family.

       EAI_AGAIN
              The  name  server returned a temporary failure indication.  Try
              again later.

       EAI_NODATA
              The  specified  network host exists, but does not have any net-
              work addresses defined.

(摘自man 3 getaddrinfo)。

实际上,似乎差别不大:

$ ./getaddr_test www.google.invalid 80
getaddrinfo returned -2 (Name or service not known), errno is errno: 2
$ sudo vim /etc/resolv.conf # point to non-existing nameserver
$ ./getaddr_test www.google.com 80
getaddrinfo returned -2 (Name or service not known), errno is errno: 2
$ ./getaddr_test www.google.invalid 80
getaddrinfo returned -2 (Name or service not known), errno is errno: 2
$ uname -o -v
#1 SMP Debian 3.14.12-1 (2014-07-11) GNU/Linux

是否有任何其他方法可以将无法解析的主机名与无法访问的 DNS 服务器区分开来(不需要我再次查找“已知良好”的主机名)?

这是我使用的测试程序的源代码:

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[]) {
  struct addrinfo hints;
  struct addrinfo *result;
  int ret;

  if (argc < 3) {
    fprintf(stderr, "Usage: %s host port...\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  memset(&hints, 0, sizeof(struct addrinfo));
  hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
  hints.ai_socktype = SOCK_STREAM; /* Stream socket */
  hints.ai_protocol = 0;          /* Any protocol */
  hints.ai_flags = 0;

  ret = getaddrinfo(argv[1], argv[2], &hints, &result);
  if (ret != 0) 
    printf("getaddrinfo returned %d (%s), errno is errno: %d\n",
           ret, gai_strerror(ret), errno);
  else
    printf("getaddrinfo succeeded.");
}

【问题讨论】:

  • 查看netdb.h后发现-2的返回值等于EAI_NONAME。

标签: c linux sockets dns


【解决方案1】:

我认为它不区分这一点的原因是它有多个信息来源来解析名称。大多数 Linux 使用 NSS 来聚合这些源,并且默认使用基于 /etc/hosts 文件的解析以及 DNS 解析(但可能是 LDAP 和其他)。

您可以使用仅将“hosts”设置为“dns”的 nsswitch.conf 文件再次尝试您的测试,但该解决方案即使有效,也不会非常可靠。

我能想象到的唯一完整的解决方案是让您完全控制这个问题,那就是自己联系 DNS 服务器。如果您无法向他们打开套接字,那么您就知道他们无法联系到他们。如果可以但名称无法解析,则您知道它的名称无效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 2012-04-18
    • 1970-01-01
    • 2018-04-15
    • 2019-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多