gcc/cygwin如何获取DNS服务器?

Posted

技术标签:

【中文标题】gcc/cygwin如何获取DNS服务器?【英文标题】:How does gcc/cygwin get the DNS server? 【发布时间】:2012-05-18 10:12:11 【问题描述】:

我在 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, "dns-s-rvr: %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服务器有什么技巧吗?

【问题讨论】:

顺便说一句,您可以使用 char buf[INET_ADDRSTRLEN]; fprintf(stderr, "dns-s-rvr: %s\n", inet_ntop(AF_INET, &amp;_res.nsaddr_list[i].sin_addr, buf, sizeof buf)); 来格式化IP地址。 好点,干净多了。谢谢。 【参考方案1】:

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

查看源代码here、文件minires.cminires-os-if.c

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

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

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

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

【讨论】:

仔细观察,如果use_os 不为零,即使是最新的cygwin 也不会填充nsaddr_list - 如果没有/etc/resolv.conf/etc/resolv.conf 包含options osquery,这是真的。因此,让 cygwin 从操作系统名称服务器列表中填写 nsaddr_list 的唯一方法是使用空的 /etc/resolv.conf @caf:是的。但我认为 Windows 上通常没有 /etc/resolv.conf 当然 - 并且有 no /etc/resolv.conf 会导致 nsaddr_list 不被填写。所以我认为让 Cygwin 特定的代码调用 GetNetworkParams() 看起来是唯一的解决方案。 @caf:我认为这是不正确的。 res_initres_ninitget_dns_infouse_os==1nscount==0)→ nscount=-1goto use_registrynsaddr_list 从那里的注册表中填充。 @caf:我现在没有要检查的 Windows 机器。 This thread 似乎表明我之前评论中概述的顺序不起作用,但我不确定为什么。【参考方案2】:

作为n.m. says,在Cygwin 上res_init() 不会填充_res.nsaddr_list,如果它使用的是Windows 解析器。如果/etc/resolv.conf 不存在,或者/etc/resolv.conf 包含options osquery,它将使用Windows 解析器。

在我看来,这是一个 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);

您需要针对-liphlpapi 链接GetNetworkParams() 函数。

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

【讨论】:

这给了我我需要的东西!谢谢。

以上是关于gcc/cygwin如何获取DNS服务器?的主要内容,如果未能解决你的问题,请参考以下文章

如何在android中获取DNS信息[重复]

ANSI C 如何在 Linux 中获取名称服务器(DNS)地址? [复制]

如何在SQL注入中使用DNS技术获取数据

如何使用 Strophe JS 获取 DNS SRV 记录?

DHCP如何添加备用DNS

如何找到当前的 DNS 服务器?