550 lines
13 KiB
C
550 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
servlist.c
|
||
|
||
Abstract:
|
||
|
||
Domain Name System (DNS) API
|
||
|
||
DNS network info routines.
|
||
|
||
Author:
|
||
|
||
Jim Gilroy (jamesg) January, 1997
|
||
Glenn Curtis (glennc) May, 1997
|
||
|
||
Revision History:
|
||
|
||
Jim Gilroy (jamesg) March 2000 slowly cleaning up
|
||
|
||
--*/
|
||
|
||
|
||
#include "local.h"
|
||
#include "registry.h" // Registry reading definitions
|
||
|
||
|
||
//
|
||
// Keep copy of DNS server/network info
|
||
//
|
||
|
||
|
||
#define CURRENT_ADAPTER_LIST_TIMEOUT (10) // 10 seconds
|
||
|
||
|
||
//
|
||
// Registry info
|
||
//
|
||
|
||
#define DNS_REG_READ_BUF_SIZE (1000)
|
||
|
||
#define LOCALHOST "127.0.0.1"
|
||
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
ParseNameServerList(
|
||
IN OUT PIP_ARRAY aipServers,
|
||
IN LPSTR pBuffer,
|
||
IN BOOL IsMultiSzString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parse DNS server list from registry into IP address array.
|
||
|
||
Arguments:
|
||
|
||
aipServers -- IP array of DNS servers
|
||
|
||
pBuffer -- buffer with IP addresses in dotted format
|
||
|
||
IsMultiSzString -- Determines how to interpret data in buffer
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
DWORD stringLength;
|
||
LPSTR pstring;
|
||
DWORD cchBufferSize = 0;
|
||
CHAR ch;
|
||
PUCHAR pchIpString;
|
||
IP_ADDRESS ip;
|
||
DWORD countServers = aipServers->AddrCount;
|
||
|
||
DNSDBG( NETINFO, (
|
||
"Parsing name server list %s\n",
|
||
pBuffer ));
|
||
|
||
//
|
||
// MULTI_SZ string
|
||
//
|
||
// IPs are given as individual strings with double NULL termination
|
||
//
|
||
|
||
if ( IsMultiSzString )
|
||
{
|
||
pstring = pBuffer;
|
||
|
||
while ( ( stringLength = strlen( pstring ) ) != 0 &&
|
||
countServers < DNS_MAX_NAME_SERVERS )
|
||
{
|
||
ip = inet_addr( pstring );
|
||
|
||
if ( ip != INADDR_ANY && ip != INADDR_NONE )
|
||
{
|
||
aipServers->AddrArray[ countServers ] = ip;
|
||
countServers++;
|
||
}
|
||
pstring += (stringLength + 1);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// extract each IP string in buffer, convert to IP address,
|
||
// and add to server IP array
|
||
//
|
||
|
||
cchBufferSize = strlen( pBuffer );
|
||
|
||
while( ch = *pBuffer && countServers < DNS_MAX_NAME_SERVERS )
|
||
{
|
||
// skip leading whitespace, find start of IP string
|
||
|
||
while( cchBufferSize > 0 &&
|
||
( ch == ' ' || ch == '\t' || ch == ',' ) )
|
||
{
|
||
ch = *++pBuffer;
|
||
cchBufferSize--;
|
||
}
|
||
pchIpString = pBuffer;
|
||
|
||
//
|
||
// find end of string and NULL terminate
|
||
//
|
||
|
||
ch = *pBuffer;
|
||
while( cchBufferSize > 0 &&
|
||
( ch != ' ' && ch != '\t' && ch != '\0' && ch != ',' ) )
|
||
{
|
||
ch = *++pBuffer;
|
||
cchBufferSize--;
|
||
}
|
||
*pBuffer = '\0';
|
||
|
||
// at end of buffer
|
||
|
||
if ( pBuffer == pchIpString )
|
||
{
|
||
DNS_ASSERT( cchBufferSize == 1 || cchBufferSize == 0 );
|
||
break;
|
||
}
|
||
|
||
//
|
||
// get IP address for string
|
||
// - zero or broadcast addresses are bogus
|
||
//
|
||
|
||
ip = inet_addr( pchIpString );
|
||
if ( ip == INADDR_ANY || ip == INADDR_NONE )
|
||
{
|
||
break;
|
||
}
|
||
aipServers->AddrArray[ countServers ] = ip;
|
||
countServers++;
|
||
|
||
// if more continue
|
||
|
||
if ( cchBufferSize > 0 )
|
||
{
|
||
pBuffer++;
|
||
cchBufferSize--;
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// reset server count
|
||
|
||
aipServers->AddrCount = countServers;
|
||
|
||
if ( aipServers->AddrCount )
|
||
{
|
||
return( ERROR_SUCCESS );
|
||
}
|
||
else
|
||
{
|
||
return( DNS_ERROR_NO_DNS_SERVERS );
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Network info structure routines
|
||
//
|
||
|
||
#if 0
|
||
PSEARCH_LIST
|
||
Dns_GetDnsSearchList(
|
||
IN LPSTR pszPrimaryDomainName,
|
||
IN HKEY hKey,
|
||
IN PDNS_NETINFO pNetworkInfo,
|
||
IN BOOL fUseDomainNameDevolution,
|
||
IN BOOL fUseDotLocalDomain
|
||
)
|
||
/*++
|
||
|
||
Dumb stub because this function is exposed in dnslib.h
|
||
and in stmpdns\servlist.cpp in iis project
|
||
|
||
DCR: eliminate this routine (stupid)
|
||
|
||
--*/
|
||
{
|
||
return SearchList_Build(
|
||
pszPrimaryDomainName,
|
||
NULL, // no reg session
|
||
hKey,
|
||
pNetworkInfo,
|
||
fUseDomainNameDevolution,
|
||
fUseDotLocalDomain );
|
||
}
|
||
#endif
|
||
|
||
|
||
VOID
|
||
Dns_ResetNetworkInfo(
|
||
IN PDNS_NETINFO pNetworkInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clear the flags for each adapter.
|
||
|
||
Arguments:
|
||
|
||
pNetworkInfo -- pointer to a DNS network info structure.
|
||
|
||
Return Value:
|
||
|
||
Nothing
|
||
|
||
--*/
|
||
{
|
||
DWORD iter;
|
||
|
||
DNSDBG( TRACE, ( "Dns_ResetNetworkInfo()\n" ));
|
||
|
||
if ( ! pNetworkInfo )
|
||
{
|
||
return;
|
||
}
|
||
|
||
for ( iter = 0; iter < pNetworkInfo->AdapterCount; iter++ )
|
||
{
|
||
pNetworkInfo->AdapterArray[iter]->RunFlags = 0;
|
||
}
|
||
|
||
pNetworkInfo->ReturnFlags = 0;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
Dns_DisableTimedOutAdapters(
|
||
IN OUT PDNS_NETINFO pNetworkInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For each adapter with status ERROR_TIMEOUT, disable it from
|
||
further retry queries till Dns_ResetNetworkInfo is called.
|
||
|
||
Arguments:
|
||
|
||
pNetworkInfo -- pointer to a DNS network info structure.
|
||
|
||
Return Value:
|
||
|
||
True if a timed out adapter was found and disabled
|
||
|
||
--*/
|
||
{
|
||
DWORD iter;
|
||
PDNS_ADAPTER padapter;
|
||
BOOL fSetAdapter = FALSE;
|
||
|
||
DNSDBG( TRACE, ( "Dns_DisableTimedOutAdapters()\n" ));
|
||
|
||
if ( ! pNetworkInfo )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
for ( iter = 0; iter < pNetworkInfo->AdapterCount; iter++ )
|
||
{
|
||
padapter = pNetworkInfo->AdapterArray[iter];
|
||
|
||
if ( padapter->Status == ERROR_TIMEOUT )
|
||
{
|
||
//
|
||
// See if the given adapters are really timing out or not.
|
||
//
|
||
// Sometimes a given name query will take a long time and
|
||
// we timeout waiting for the response, though the server
|
||
// will quicky respond to other name queries. Other times
|
||
// the default gateway doesn't let us reach the DNS servers
|
||
// on a given adapter, or they are plain dead.
|
||
//
|
||
// Pinging the given DNS servers to see if they can respond
|
||
// to a simple query helps to avoid the confusion.
|
||
//
|
||
|
||
if ( !Dns_PingAdapterServers( padapter ) )
|
||
{
|
||
padapter->RunFlags |= RUN_FLAG_IGNORE_ADAPTER;
|
||
padapter->RunFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
|
||
fSetAdapter = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( fSetAdapter )
|
||
{
|
||
pNetworkInfo->ReturnFlags = RUN_FLAG_RESET_SERVER_PRIORITY;
|
||
}
|
||
|
||
return fSetAdapter;
|
||
}
|
||
|
||
|
||
BOOL
|
||
Dns_ShouldNameErrorBeCached(
|
||
IN PDNS_NETINFO pNetworkInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used in conjuction with a given query's NAME_ERROR
|
||
response to see if the error was one that occured on all adapters.
|
||
This is used to decide if the name error response should be cached
|
||
or not. If the machine was multihomed, and one of the adapters had
|
||
a timeout error, then the name error should not be cached as a
|
||
negative response.
|
||
|
||
Arguments:
|
||
|
||
pNetworkInfo -- pointer to a DNS network info structure.
|
||
|
||
Return Value:
|
||
|
||
False if a timed out adapter was found, and name error should not
|
||
be negatively cached.
|
||
|
||
--*/
|
||
{
|
||
DWORD iter;
|
||
PDNS_ADAPTER padapter;
|
||
|
||
DNSDBG( TRACE, ( "Dns_DidNameErrorOccurEverywhere()\n" ));
|
||
|
||
if ( ! pNetworkInfo )
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
if ( pNetworkInfo->ReturnFlags & RUN_FLAG_RESET_SERVER_PRIORITY )
|
||
{
|
||
for ( iter = 0; iter < pNetworkInfo->AdapterCount; iter++ )
|
||
{
|
||
padapter = pNetworkInfo->AdapterArray[iter];
|
||
|
||
if ( !( padapter->InfoFlags & DNS_FLAG_IGNORE_ADAPTER ) &&
|
||
padapter->Status == ERROR_TIMEOUT )
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
Dns_PingAdapterServers(
|
||
IN PDNS_ADAPTER pAdapterInfo
|
||
)
|
||
//
|
||
// DCR: Dns_PingAdapterServers() is stupid
|
||
// why are we doing this?
|
||
//
|
||
{
|
||
BOOL fPing = TRUE;
|
||
PDNS_NETINFO pnetworkInfo = NULL;
|
||
PDNS_ADAPTER padapterCopy = NULL;
|
||
DNS_STATUS Status = NO_ERROR;
|
||
|
||
DNSDBG( TRACE, ( "Dns_PingAdapterServers()\n" ));
|
||
|
||
pnetworkInfo = NetInfo_Alloc( 1 );
|
||
if ( !pnetworkInfo )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
padapterCopy = AdapterInfo_Copy( pAdapterInfo );
|
||
if ( !padapterCopy )
|
||
{
|
||
NetInfo_Free( pnetworkInfo );
|
||
return FALSE;
|
||
}
|
||
|
||
padapterCopy->InfoFlags = DNS_FLAG_IS_AUTONET_ADAPTER;
|
||
|
||
NetInfo_AddAdapter(
|
||
pnetworkInfo,
|
||
padapterCopy );
|
||
|
||
//
|
||
// query adapter's DNS servers
|
||
// - query for loopback which always exists
|
||
//
|
||
|
||
Status = QueryDirectEx(
|
||
NULL, // no message
|
||
NULL, // no results
|
||
NULL, // no header
|
||
0, // no header counts
|
||
"1.0.0.127.in-addr.arpa.",
|
||
DNS_TYPE_PTR,
|
||
NULL, // no input records
|
||
DNS_QUERY_ACCEPT_PARTIAL_UDP |
|
||
DNS_QUERY_NO_RECURSION,
|
||
NULL, // no server list
|
||
pnetworkInfo );
|
||
|
||
NetInfo_Free( pnetworkInfo );
|
||
|
||
if ( Status == ERROR_TIMEOUT )
|
||
{
|
||
fPing = FALSE;
|
||
}
|
||
|
||
return fPing;
|
||
}
|
||
|
||
|
||
|
||
#if 0
|
||
//
|
||
// this is some stuff Glenn wrote for the case where you
|
||
// don't have a DNS server list and will get it through mcast
|
||
//
|
||
// it was in the middle of the NetworkInfo building routine
|
||
//
|
||
else
|
||
{
|
||
//
|
||
// DCR: functionalize multicast query attempt
|
||
//
|
||
//
|
||
// See if we can find a DNS server address to put on this
|
||
// adapter by multicasting for it . . .
|
||
//
|
||
|
||
// LevonE is still debating this method for
|
||
// server detection. If this is ultimately utilized, it
|
||
// might be better to direct the multicast query out the
|
||
// specific adapter IP address to try to get an address
|
||
// relevant to the specific adapter's network. This
|
||
// could be done by building a dummy pNetworkInfo
|
||
// parameter to pass down to Dns_QueryLib. The helper
|
||
// routine Dns_SendAndRecvMulticast could be revised to
|
||
// support specific adapter multicasting, etc.
|
||
|
||
PDNS_RECORD pServer = NULL;
|
||
|
||
status = Dns_QueryLib(
|
||
NULL,
|
||
&pServer,
|
||
(PDNS_NAME) MULTICAST_DNS_SRV_RECORD_NAME,
|
||
DNS_TYPE_SRV,
|
||
DNS_QUERY_MULTICAST_ONLY,
|
||
NULL,
|
||
NULL, // May want to specify network!
|
||
0 );
|
||
|
||
if ( status )
|
||
{
|
||
//
|
||
// This adapter is not going to have any configured
|
||
// DNS servers. No point trying any DNS queries on
|
||
// it then.
|
||
//
|
||
adapterFlags |= DNS_FLAG_IGNORE_ADAPTER;
|
||
}
|
||
else
|
||
{
|
||
if ( pServer &&
|
||
pServer->Flags.S.Section == DNSREC_ANSWER &&
|
||
pServer->wType == DNS_TYPE_SRV &&
|
||
pServer->Data.SRV.wPort == DNS_PORT_HOST_ORDER )
|
||
{
|
||
PDNS_RECORD pNext = pServer->pNext;
|
||
|
||
while ( pNext )
|
||
{
|
||
if ( pNext->Flags.S.Section == DNSREC_ADDITIONAL &&
|
||
pNext->wType == DNS_TYPE_A &&
|
||
Dns_NameCompare( pServer ->
|
||
Data.SRV.pNameTarget,
|
||
pNext->pName ) )
|
||
{
|
||
pserverIpArray->AddrCount = 1;
|
||
pserverIpArray->AddrArray[0] =
|
||
pNext->Data.A.IpAddress;
|
||
adapterFlags |= DNS_FLAG_AUTO_SERVER_DETECTED;
|
||
break;
|
||
}
|
||
|
||
pNext = pNext->pNext;
|
||
}
|
||
}
|
||
|
||
Dns_RecordListFree( pServer );
|
||
|
||
if ( pserverIpArray->AddrCount == 0 )
|
||
{
|
||
//
|
||
// This adapter is not going to have any configured
|
||
// DNS servers. No point trying any DNS queries on
|
||
// it then.
|
||
//
|
||
adapterFlags |= DNS_FLAG_IGNORE_ADAPTER;
|
||
}
|
||
}
|
||
}
|
||
#endif // multicast attempt
|
||
|
||
//
|
||
// End servlist.c
|
||
//
|
||
|