8

我有一些我正在 cygwin 下编写的代码(使用 GCC)成功使用 gethostbyname(); 但是,当我尝试直接使用解析器来检索 DNS 服务器的 IP 地址时,它会失败(nsaddr_list[] 中的所有条目都为空,nscount 为 -1)。如果 gethostbyname() 工作正常,那么显然它能够连接到 DNS 服务器。
这段代码...

    if (res_init() == -1) {
        fprintf(stderr,"res_init() failed\n");
        exit(1);
    }

    if (_res.nscount <= 0) {
        fprintf(stderr,"nscount = %d\n",_res.nscount);
    }
    else {
        for(i=0;i<_res.nscount;i++) {
            fprintf(stderr, "dnssrvr: %d.%d.%d.%d\n",
                (_res.nsaddr_list[i].sin_addr.s_addr & 0xff) >> 0,
                (_res.nsaddr_list[i].sin_addr.s_addr & 0xff00) >> 8,
                (_res.nsaddr_list[i].sin_addr.s_addr & 0xff0000) >> 16,
                (_res.nsaddr_list[i].sin_addr.s_addr & 0xff000000) >> 24);
        }
    }

适用于 unix/linux,但在 cygwin 上返回 nscount=-1。使用 cygwin/gcc 时获取 DNS 服务器有什么技巧吗?

4

2 回答 2

3

res_init不一定填充_res.nsaddr_list。相反,在 Windows 上,它指示解析器使用DnsQuery_A除非您拥有该resolv.conf文件,在这种情况下,将使用该文件中的 DNS 服务器。

在此处查看源代码、文件minires.cminires-os-if.c.

如果您需要了解您的 DNS 服务器,您可能必须使用DnsQueryConfigGetNetworkParams

注意:_res未记录,不应使用。

更新 显然,cygwin 的“较新”(ca 2010 及更高版本)版本确实填充_res.nsaddr_list,通过调用get_dns_info然后get_registry_dns。您可能需要确保您拥有最新的 cygwin,如果问题仍然存在,请尝试使用调试版本并跟踪对上述函数的调用。

更新 2不,_res没有填充,我的错误。

于 2012-05-27T10:32:16.577 回答
2

正如nm 所说,如果 Cygwin使用的是 Windows 解析器,res_init()则不会填充。_res.nsaddr_list如果/etc/resolv.conf不存在或/etc/resolv.conf包含options osquery.

在我看来,这是一个 Cygwin 错误 - 返回负数nscount是虚假的 - 但我们仍然坚持解决它。

GetNetworkParams()解决方案是像 Cygwin 本身一样调用- 这就是我正在做的后备:

#include <windows.h>
#include <iphlpapi.h>
#include <netinet/in.h>
#include <arpa/inet.h>

if (_res.nscount < 0)
{
    ULONG buflen = 0;
    FIXED_INFO *buf = NULL;

    if (GetNetworkParams(NULL, &buflen) == ERROR_BUFFER_OVERFLOW)
        buf = malloc(buflen);

    if (buf && GetNetworkParams(buf, &buflen) == NO_ERROR)
    {
        _res.nscount = 1;
        _res.nsaddr_list[0].sin_family = AF_INET;
        _res.nsaddr_list[0].sin_addr.s_addr = inet_addr(buf->DnsServerList.IpAddress.String);
        _res.nsaddr_list[0].sin_port = htons(53);
    }

    free(buf);
}

您需要针对-liphlpapiGetNetworkParams()功能进行链接。

这仅需要第一个 Windows DNS 地址,但如果您想要其余的地址,您可以按照GetNetworkParams()返回的链接列表进行操作。 GetNetworkParams()只返回 IPv4 地址,如果机器配置了 IPv6 DNS 服务器地址,我不确定你应该做什么。

于 2012-06-01T03:25:37.030 回答