Reputation: 966
I have some code I'm writing under cygwin (using GCC) that successfully uses gethostbyname(); however when I try to use the resolver directly to retrieve the IP address of the DNS server it fails (all entries in nsaddr_list[] are null and nscount is -1).
If gethostbyname() is working, then obviously it is able to connect to the DNS server.
This code...
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);
}
}
works on unix/linux, but returns nscount=-1 on cygwin. Is there some trick to getting the DNS server when using cygwin/gcc?
Upvotes: 8
Views: 7761
Reputation: 239041
As n.m. says, on Cygwin res_init()
does not populate _res.nsaddr_list
if it is using the Windows resolver. It uses the Windows resolver if either /etc/resolv.conf
does not exist, or /etc/resolv.conf
contains options osquery
.
In my opinion this is a Cygwin bug - returning a negative nscount
is bogus - but nonetheless we are stuck with working around it.
The solution is to call GetNetworkParams()
just as Cygwin does itself - here's what I'm doing as a fallback:
#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);
}
You need to link against -liphlpapi
for the GetNetworkParams()
function.
This only takes the first Windows DNS address, but if you want the rest of them you can follow the linked list that GetNetworkParams()
returns. GetNetworkParams()
only returns IPv4 addresses, I'm not sure what you're supposed to do if the machine has an IPv6 DNS server address configured.
Upvotes: 2
Reputation: 119877
res_init
does not necessarily populate _res.nsaddr_list
. Instead, on Windows it directs the resolver to use DnsQuery_A
, unless you have the resolv.conf
file, in which case DNS servers from that file are used.
See the source here, files minires.c
and minires-os-if.c
.
If you need to know your DNS servers, you probably have to use DnsQueryConfig
or GetNetworkParams
.
NB: _res
is undocumented and should not be used.
UPDATE Apparently the "newer" (ca 2010 and later) versions of cygwin do populate _res.nsaddr_list
, via a call to get_dns_info
and then get_registry_dns
. You may want to make sure that you have the newest cygwin, and if the problem persists, try to use a debug version and trace calls to the mentioned functions.
UPDATE 2 No, _res
is not populated, my mistake.
Upvotes: 3