/*
* V4. Get the physical address of the first NIC whose list of DNS servers contain 'addr'.
* return: ARES_SUCCESS, etc.
*/
static int get_physical_address(char *physicalAddr, int physicalAddrBufSz, int* physAddrLen, struct in_addr addr)
{
#ifdef WIN32
DWORD (WINAPI * GetAdaptersAddressesProc)(ULONG, DWORD, VOID *, IP_ADAPTER_ADDRESSES *, ULONG *);
HANDLE hLib = 0;
DWORD dwRet = ERROR_BUFFER_OVERFLOW;
DWORD dwSize = 0;
IP_ADAPTER_ADDRESSES *pAdapterAddresses = 0;
int rc = ARES_ENOTFOUND;
memset(physicalAddr, '\0', physicalAddrBufSz);
*physAddrLen = 0;
hLib = LoadLibrary(TEXT("iphlpapi.dll"));
if (!hLib)
return ARES_ENOTIMP;
(void*)GetAdaptersAddressesProc = GetProcAddress(hLib, TEXT("GetAdaptersAddresses"));
if(!GetAdaptersAddressesProc)
{
rc = ARES_ENOTIMP;
goto cleanup;
}
// Getting buffer size, expects overflow error
dwRet = (*GetAdaptersAddressesProc)(AF_UNSPEC, 0, NULL, NULL, &dwSize);
assert(dwRet == ERROR_BUFFER_OVERFLOW);
if (dwRet == ERROR_BUFFER_OVERFLOW)
{
pAdapterAddresses = (IP_ADAPTER_ADDRESSES *) LocalAlloc(LMEM_ZEROINIT, dwSize);
if (! pAdapterAddresses)
{
rc = ARES_ENOMEM;
goto cleanup;
}
}
else
{
rc = ARES_ENODATA;
goto cleanup;
}
dwRet = (*GetAdaptersAddressesProc)(AF_UNSPEC, 0, NULL, pAdapterAddresses, &dwSize);
if (dwRet != ERROR_SUCCESS)
{
rc = ARES_ENODATA;
goto cleanup;
}
{
IP_ADAPTER_ADDRESSES * AI = NULL;
for (AI = pAdapterAddresses; AI != NULL; AI = AI->Next)
{
PIP_ADAPTER_DNS_SERVER_ADDRESS dnsServers = AI->FirstDnsServerAddress;
// find 'addr' in adapter's list of dns servers.
for (; dnsServers; dnsServers = dnsServers->Next)
{
if (! dnsServers->Address.lpSockaddr)
continue;
if (dnsServers->Address.lpSockaddr->sa_family == AF_INET)
{
struct sockaddr_in sockAddr = *(struct sockaddr_in*)(dnsServers->Address.lpSockaddr);
if (memcmp(&addr, &sockAddr.sin_addr.s_addr, sizeof(struct in_addr)) == 0)
{
*physAddrLen = AI->PhysicalAddressLength;
if (*physAddrLen > physicalAddrBufSz)
*physAddrLen = physicalAddrBufSz;
memcpy(physicalAddr, &AI->PhysicalAddress[0], *physAddrLen);
rc = ARES_SUCCESS;
goto cleanup;
}
}
}
}
}
rc = ARES_ENOTFOUND;
cleanup:
if (hLib)
FreeLibrary(hLib);
if (pAdapterAddresses)
LocalFree(pAdapterAddresses);
return rc;
#else // WIN32
return ARES_ENOTIMP;
#endif // WIN32
}
#ifdef WIN32
static int init_by_defaults_windows_nameservers_getadaptersaddresses(ares_channel channel)
{
/*
* Way of getting nameservers that should work on all Windows from 98 on.
*/
FIXED_INFO * FixedInfo;
ULONG ulOutBufLen;
DWORD dwRetVal;
IP_ADDR_STRING * pIPAddr;
HANDLE hLib;
int num;
DWORD (WINAPI *GetNetworkParams)(FIXED_INFO*, DWORD*);
hLib = LoadLibrary(TEXT("iphlpapi.dll"));
if(!hLib)
{
return ARES_ENOTIMP;
}
(void*)GetNetworkParams = GetProcAddress(hLib, TEXT("GetNetworkParams"));
if(!GetNetworkParams)
{
FreeLibrary(hLib);
return ARES_ENOTIMP;
}
//printf("ARES: figuring out DNS servers\n");
FixedInfo = (FIXED_INFO *) GlobalAlloc( GPTR, sizeof( FIXED_INFO ) );
ulOutBufLen = sizeof( FIXED_INFO );
if( ERROR_BUFFER_OVERFLOW == (*GetNetworkParams)( FixedInfo, &ulOutBufLen ) )
{
GlobalFree( FixedInfo );
FixedInfo = (FIXED_INFO *)GlobalAlloc( GPTR, ulOutBufLen );
}
if ( dwRetVal = (*GetNetworkParams)( FixedInfo, &ulOutBufLen ) )
{
//printf("ARES: couldn't get network params\n");
GlobalFree( FixedInfo );
FreeLibrary(hLib);
return ARES_ENODATA;
}
else
{
/**
printf( "Host Name: %s\n", FixedInfo -> HostName );
printf( "Domain Name: %s\n", FixedInfo -> DomainName );
printf( "DNS Servers:\n" );
printf( "\t%s\n", FixedInfo -> DnsServerList.IpAddress.String );
**/
// Count how many nameserver entries we have and allocate memory for them.
num = 0;
pIPAddr = &FixedInfo->DnsServerList;
while ( pIPAddr && strlen(pIPAddr->IpAddress.String) > 0)
{
num++;
pIPAddr = pIPAddr ->Next;
}
if(num>0)
{
channel->servers = malloc( (num) * sizeof(struct server_state));
if (!channel->servers)
{
GlobalFree( FixedInfo );
FreeLibrary(hLib);
return ARES_ENOMEM;
}
memset(channel->servers, '\0', num * sizeof(struct server_state));
channel->nservers = 0;
pIPAddr = &FixedInfo->DnsServerList;
while ( pIPAddr && strlen(pIPAddr->IpAddress.String) > 0)
{
struct in_addr addr;
addr.s_addr = inet_addr(pIPAddr->IpAddress.String);
// append unique only
if (find_server(channel->servers, channel->nservers, addr) == -1)
{
// printf( "ARES: %s\n", pIPAddr ->IpAddress.String );
#ifdef USE_IPV6
channel->servers[ channel->nservers ].family = AF_INET;
#endif
channel->servers[channel->nservers].addr = addr;
if ((channel->flags & ARES_FLAG_TRY_NEXT_SERVER_ON_RCODE3))
{
get_physical_address(channel->servers[channel->nservers].physical_addr,
MAX_ADAPTER_ADDRESS_LENGTH,
&channel->servers[channel->nservers].physical_addr_len,
addr);
}
channel->nservers++;
}
pIPAddr = pIPAddr ->Next;
}
//printf("ARES: got all %d nameservers\n",num);
}
else
{
/* If no specified servers, try a local named. */
channel->servers = malloc(sizeof(struct server_state));
if (!channel->servers)
return ARES_ENOMEM;
memset(channel->servers, '\0', sizeof(struct server_state));
#ifdef USE_IPV6
channel->servers[0].family = AF_INET;
#endif
channel->servers[0].addr.s_addr = htonl(INADDR_LOOPBACK);
channel->servers[0].default_localhost_server = 1;
channel->nservers = 1;
}
GlobalFree( FixedInfo );
FreeLibrary(hLib);
}
return ARES_SUCCESS;
}