2012-05-09 11 views
8

Tengo un código que estoy escribiendo bajo cygwin (usando GCC) que usa con éxito gethostbyname(); sin embargo, cuando trato de usar el resolver directamente para recuperar la dirección IP del servidor DNS, falla (todas las entradas en nsaddr_list [] son ​​nulas y nscount es -1). Si gethostbyname() está funcionando, entonces obviamente puede conectarse al servidor DNS.
Este código ...¿Cómo obtiene gcc/cygwin el servidor 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); 
     } 
    } 

obras en Unix/Linux, pero vuelve NSCOUNT = -1 en cygwin. ¿Hay algún truco para obtener el servidor DNS cuando se usa cygwin/gcc?

+0

Como un aparte, puede usar '{char buf [INET_ADDRSTRLEN]; fprintf (stderr, "dnssrvr:% s \ n", inet_ntop (AF_INET, & _res.nsaddr_list [i] .sin_addr, buf, sizeof buf)); } 'para formatear la dirección IP. – caf

+0

Buen punto, mucho más limpio. Gracias. –

Respuesta

2

Como n.m. says, en Cygwin res_init() no se rellena _res.nsaddr_list si está utilizando la resolución de Windows. Utiliza la resolución de Windows si /etc/resolv.conf no existe o /etc/resolv.conf contiene options osquery.

En mi opinión, esto es un error de Cygwin - devolver un nscount negativo es falso - pero no obstante, estamos trabajados con el trabajo a su alrededor.

La solución es llamar GetNetworkParams() al igual que lo hace en sí Cygwin - esto es lo que estoy haciendo como un mensaje:

#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); 
} 

es necesario enlazar contra -liphlpapi para la función GetNetworkParams().

Esto solo toma la primera dirección DNS de Windows, pero si desea el resto de ellos, puede seguir la lista vinculada que devuelve GetNetworkParams(). GetNetworkParams() solo devuelve direcciones IPv4, no estoy seguro de lo que se supone que debe hacer si la máquina tiene una dirección de servidor DNS IPv6 configurada.

+1

¡Esto me da lo que necesito! Gracias. –

3

res_init no rellena necesariamente _res.nsaddr_list. En cambio, en Windows ordena a la resolución que use DnsQuery_A, a menos que tenga el archivo resolv.conf, en cuyo caso se utilizan servidores DNS de ese archivo.

Ver la fuente here, archivos minires.c y minires-os-if.c.

Si necesita conocer sus servidores DNS, probablemente tenga que usar DnsQueryConfig o GetNetworkParams.

NB: _res no está documentado y no debe utilizarse.

ACTUALIZACIÓN Al parecer, el "nuevo" (ca 2010 y posterior) versiones de cygwin no pueblan _res.nsaddr_list, a través de una llamada a get_dns_info y luego get_registry_dns. Es posible que desee asegurarse de tener el cygwin más reciente y, si el problema persiste, intente utilizar una versión de depuración y rastrear llamadas a las funciones mencionadas.

ACTUALIZACIÓN 2 No, _res no está ocupado, mi error.

+0

Mirando de cerca, incluso el cygwin más nuevo no llena el 'nsaddr_list' si' use_os' no es cero, esto es cierto si no hay '/ etc/resolv.conf' o si'/etc/resolv.conf' contiene ' opciones osquery'. Por lo tanto, la única forma de que cygwin llene 'nsaddr_list' de la lista de servidores de nombres del sistema operativo es tener un'/etc/resolv.conf' vacío. – caf

+0

@caf: sí. pero creo que normalmente no hay '/ etc/resolv.conf' en Windows –

+0

Claro - y tener * no *'/etc/resolv.conf' hace que 'nsaddr_list' no se complete. Así que creo que tener el código específico de Cygwin para llamar a 'GetNetworkParams()' se ve como la única solución. – caf

Cuestiones relacionadas