3248 lines
67 KiB
C
3248 lines
67 KiB
C
/*++
|
||
|
||
Copyright (c) 2000-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
netinfo.c
|
||
|
||
Abstract:
|
||
|
||
Domain Name System (DNS) API
|
||
|
||
DNS network info routines.
|
||
|
||
Author:
|
||
|
||
Jim Gilroy (jamesg) March 2000
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "local.h"
|
||
#include "registry.h" // Registry reading definitions
|
||
|
||
|
||
//
|
||
// Registry info
|
||
//
|
||
|
||
#define DNS_REG_READ_BUF_SIZE (1000)
|
||
|
||
#define LOCALHOST "127.0.0.1"
|
||
|
||
|
||
//
|
||
// Netinfo cache
|
||
//
|
||
// Do in process caching of netinfo for brief period for perf
|
||
// Currently cache for only 10s
|
||
// Locking currently just using general CS
|
||
//
|
||
|
||
PDNS_NETINFO g_pNetInfo = NULL;
|
||
|
||
#define NETINFO_CACHE_TIMEOUT (10) // 10 seconds
|
||
|
||
#define LOCK_NETINFO() LOCK_GENERAL()
|
||
#define UNLOCK_NETINFO() UNLOCK_GENERAL()
|
||
|
||
|
||
|
||
|
||
//
|
||
// Adapter info routines
|
||
//
|
||
|
||
DWORD
|
||
AdapterInfo_SizeForServerCount(
|
||
IN DWORD ServerCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Size in bytes of adapter info for given server count.
|
||
|
||
Arguments:
|
||
|
||
ServerCount -- max count of servers adapter will hold
|
||
|
||
Return Value:
|
||
|
||
Size in bytes of ADAPTER_INFO blob.
|
||
|
||
--*/
|
||
{
|
||
return sizeof(DNS_ADAPTER)
|
||
- sizeof(DNS_SERVER_INFO)
|
||
+ (sizeof(DNS_SERVER_INFO) * ServerCount);
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADAPTER
|
||
AdapterInfo_Alloc(
|
||
IN DWORD ServerCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create uninitialized DNS Server list.
|
||
|
||
Arguments:
|
||
|
||
ServerCount -- count of servers list will hold
|
||
|
||
Return Value:
|
||
|
||
Ptr to uninitialized adapter, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, ( "AdapterInfo_Alloc()\n" ));
|
||
|
||
//
|
||
// allocate blob for adapter info
|
||
//
|
||
|
||
return (PDNS_ADAPTER)
|
||
ALLOCATE_HEAP_ZERO(
|
||
AdapterInfo_SizeForServerCount( ServerCount ) );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
AdapterInfo_Free(
|
||
IN OUT PDNS_ADAPTER pAdapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free DNS_ADAPTER structure.
|
||
|
||
Arguments:
|
||
|
||
pAdapter -- pointer to adapter blob to free
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, ( "AdapterInfo_Free( %p )\n", pAdapter ));
|
||
|
||
if ( !pAdapter )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if ( pAdapter->pszAdapterGuidName )
|
||
{
|
||
FREE_HEAP( pAdapter->pszAdapterGuidName );
|
||
}
|
||
if ( pAdapter->pszAdapterDomain )
|
||
{
|
||
FREE_HEAP( pAdapter->pszAdapterDomain );
|
||
}
|
||
if ( pAdapter->pAdapterIPAddresses )
|
||
{
|
||
FREE_HEAP( pAdapter->pAdapterIPAddresses );
|
||
}
|
||
if ( pAdapter->pAdapterIPSubnetMasks )
|
||
{
|
||
FREE_HEAP( pAdapter->pAdapterIPSubnetMasks );
|
||
}
|
||
FREE_HEAP( pAdapter );
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADAPTER
|
||
AdapterInfo_Copy(
|
||
IN PDNS_ADAPTER pAdapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of DNS adapter info.
|
||
|
||
Arguments:
|
||
|
||
pAdapter -- DNS adapter to copy
|
||
|
||
Return Value:
|
||
|
||
Ptr to DNS adapter info copy, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADAPTER pcopy;
|
||
|
||
DNSDBG( TRACE, ( "AdapterInfo_Copy( %p )\n", pAdapter ));
|
||
|
||
if ( ! pAdapter )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
pcopy = AdapterInfo_Alloc( pAdapter->ServerCount );
|
||
if ( ! pcopy )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// copy the whole blob
|
||
// - reset MaxServerCount to actual allocation
|
||
|
||
RtlCopyMemory(
|
||
pcopy,
|
||
pAdapter,
|
||
AdapterInfo_SizeForServerCount( pAdapter->ServerCount ) );
|
||
|
||
pcopy->MaxServerCount = pAdapter->ServerCount;
|
||
|
||
// fixup allocated subfields
|
||
|
||
pcopy->pszAdapterGuidName = Dns_CreateStringCopy(
|
||
pAdapter->pszAdapterGuidName,
|
||
0 );
|
||
|
||
pcopy->pszAdapterDomain = Dns_CreateStringCopy(
|
||
pAdapter->pszAdapterDomain,
|
||
0 );
|
||
|
||
pcopy->pAdapterIPAddresses = Dns_CreateIpArrayCopy(
|
||
pAdapter->pAdapterIPAddresses );
|
||
|
||
pcopy->pAdapterIPSubnetMasks = Dns_CreateIpArrayCopy(
|
||
pAdapter->pAdapterIPSubnetMasks );
|
||
return( pcopy );
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADAPTER
|
||
AdapterInfo_Create(
|
||
IN DWORD ServerCount,
|
||
IN DWORD dwFlags,
|
||
IN PSTR pszDomain,
|
||
IN PSTR pszGuidName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create uninitialized DNS Server list.
|
||
|
||
Arguments:
|
||
|
||
ServerCount -- count of servers list will hold
|
||
|
||
dwFlags -- flags
|
||
|
||
pszAdapterDomain -- the names of the domain associated with this
|
||
interface
|
||
|
||
pszGuidName -- GUID name
|
||
|
||
Return Value:
|
||
|
||
Ptr to adapter info, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADAPTER padapter = NULL;
|
||
|
||
DNSDBG( TRACE, ( "AdapterInfo_Create()\n" ));
|
||
|
||
//
|
||
// allocate blob for adapter info
|
||
//
|
||
|
||
padapter = AdapterInfo_Alloc( ServerCount );
|
||
if ( ! padapter )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
DNS_ASSERT( padapter->RunFlags == 0 );
|
||
DNS_ASSERT( padapter->ServerCount == 0 );
|
||
|
||
padapter->pszAdapterGuidName = Dns_CreateStringCopy( pszGuidName, 0 );
|
||
padapter->pszAdapterDomain = Dns_CreateStringCopy( pszDomain, 0 );
|
||
|
||
padapter->MaxServerCount = ServerCount;
|
||
padapter->InfoFlags = dwFlags;
|
||
|
||
return padapter;
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADAPTER
|
||
AdapterInfo_CreateFromIpArray(
|
||
IN PIP_ARRAY pServerArray,
|
||
IN DWORD dwFlags,
|
||
IN PSTR pszDomainName,
|
||
IN PSTR pszGuidName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of IP address array as a DNS Server list.
|
||
|
||
Arguments:
|
||
|
||
pIpArray -- IP address array to convert
|
||
|
||
dwFlags -- Flags that describe the adapter
|
||
|
||
pszDomainName -- The default domain name for the adapter
|
||
|
||
pszGuidName -- The registry GUID name for the adapter (if NT)
|
||
|
||
Return Value:
|
||
|
||
Ptr to DNS Server list copy, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADAPTER padapter;
|
||
DWORD i;
|
||
DWORD count;
|
||
|
||
DNSDBG( TRACE, ( "AdapterInfo_CreateFromIpArray()\n" ));
|
||
|
||
//
|
||
// get count of DNS servers
|
||
//
|
||
|
||
if ( !pServerArray )
|
||
{
|
||
count = 0;
|
||
}
|
||
else
|
||
{
|
||
count = pServerArray->AddrCount;
|
||
}
|
||
|
||
//
|
||
// create adapter with server list of required size
|
||
//
|
||
|
||
padapter = AdapterInfo_Create(
|
||
count,
|
||
dwFlags,
|
||
pszDomainName,
|
||
pszGuidName );
|
||
if ( !padapter )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// copy DNS server IPs and clear other fields
|
||
//
|
||
// DCR_QUESTION: are fields already zero'd?
|
||
//
|
||
|
||
for ( i=0; i < count; i++ )
|
||
{
|
||
padapter->ServerArray[i].IpAddress = pServerArray->AddrArray[i];
|
||
padapter->ServerArray[i].Status = NO_ERROR;
|
||
padapter->ServerArray[i].Priority = 0;
|
||
}
|
||
padapter->ServerCount = count;
|
||
|
||
return padapter;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Search list routines
|
||
//
|
||
|
||
PSEARCH_LIST
|
||
SearchList_Alloc(
|
||
IN DWORD MaxNameCount,
|
||
IN PSTR pszName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create uninitialized search list.
|
||
|
||
Arguments:
|
||
|
||
NameCount -- count of search names list will hold
|
||
|
||
pszName -- primary domain name
|
||
|
||
Return Value:
|
||
|
||
Ptr to uninitialized DNS search list, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PSEARCH_LIST psearchList = NULL;
|
||
DWORD length;
|
||
|
||
DNSDBG( TRACE, ( "SearchList_Create()\n" ));
|
||
|
||
if ( MaxNameCount == 0 && !pszName )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// allocate for max entries
|
||
//
|
||
|
||
length = sizeof(SEARCH_LIST)
|
||
- sizeof(SEARCH_NAME)
|
||
+ ( sizeof(SEARCH_NAME) * MaxNameCount );
|
||
|
||
psearchList = (PSEARCH_LIST) ALLOCATE_HEAP_ZERO( length );
|
||
if ( ! psearchList )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
psearchList->MaxNameCount = MaxNameCount;
|
||
|
||
if ( pszName )
|
||
{
|
||
psearchList->pszDomainOrZoneName = Dns_CreateStringCopy( pszName, 0 );
|
||
if ( ! psearchList->pszDomainOrZoneName )
|
||
{
|
||
FREE_HEAP( psearchList );
|
||
return NULL;
|
||
}
|
||
}
|
||
return psearchList;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
SearchList_Free(
|
||
IN OUT PSEARCH_LIST pSearchList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free SEARCH_LIST structure.
|
||
|
||
Arguments:
|
||
|
||
pSearchList -- ptr to search list to free
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DWORD i;
|
||
|
||
DNSDBG( TRACE, ( "SearchList_Free( %p )\n", pSearchList ));
|
||
|
||
//
|
||
// DCR: eliminate search list DomainOrZoneName
|
||
//
|
||
|
||
if ( pSearchList )
|
||
{
|
||
if ( pSearchList->pszDomainOrZoneName )
|
||
{
|
||
FREE_HEAP( pSearchList->pszDomainOrZoneName );
|
||
}
|
||
|
||
for ( i=0; i < pSearchList->MaxNameCount; i++ )
|
||
{
|
||
PSTR pname = pSearchList->SearchNameArray[i].pszName;
|
||
if ( pname )
|
||
{
|
||
FREE_HEAP( pname );
|
||
}
|
||
}
|
||
|
||
FREE_HEAP( pSearchList );
|
||
}
|
||
}
|
||
|
||
|
||
|
||
PSEARCH_LIST
|
||
SearchList_Copy(
|
||
IN PSEARCH_LIST pSearchList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of search list.
|
||
|
||
Arguments:
|
||
|
||
pSearchList -- search list to copy
|
||
|
||
Return Value:
|
||
|
||
Ptr to DNS Search list copy, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PSEARCH_LIST pcopy;
|
||
DWORD i;
|
||
|
||
DNSDBG( TRACE, ( "SearchList_Copy()\n" ));
|
||
|
||
if ( ! pSearchList )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// create DNS Search list of desired size
|
||
//
|
||
// since we don't add and delete from search list once
|
||
// created, size copy only for actual name count
|
||
//
|
||
|
||
pcopy = SearchList_Alloc(
|
||
pSearchList->NameCount,
|
||
pSearchList->pszDomainOrZoneName );
|
||
if ( ! pcopy )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
for ( i=0; i < pSearchList->NameCount; i++ )
|
||
{
|
||
PSTR pname = pSearchList->SearchNameArray[i].pszName;
|
||
|
||
if ( pname )
|
||
{
|
||
pname = Dns_CreateStringCopy(
|
||
pname,
|
||
0 );
|
||
if ( pname )
|
||
{
|
||
pcopy->SearchNameArray[i].pszName = pname;
|
||
pcopy->SearchNameArray[i].Flags =
|
||
pSearchList->SearchNameArray[i].Flags;
|
||
pcopy->NameCount++;
|
||
}
|
||
}
|
||
}
|
||
|
||
return pcopy;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
SearchList_ContainsName(
|
||
IN PSEARCH_LIST pSearchList,
|
||
IN PSTR pszName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check if name is in search list.
|
||
|
||
Arguments:
|
||
|
||
pSearchList -- ptr to search list being built
|
||
|
||
pszName -- name to check
|
||
|
||
Return Value:
|
||
|
||
TRUE if name is in search list.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
DWORD count = pSearchList->NameCount;
|
||
|
||
//
|
||
// check every search list entry for this name
|
||
//
|
||
|
||
while ( count-- )
|
||
{
|
||
if ( Dns_NameCompare_UTF8(
|
||
pSearchList->SearchNameArray[ count ].pszName,
|
||
pszName ) )
|
||
{
|
||
return( TRUE );
|
||
}
|
||
}
|
||
return( FALSE );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
SearchList_AddName(
|
||
IN OUT PSEARCH_LIST pSearchList,
|
||
IN PSTR pszName,
|
||
IN DWORD Flag
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Add name to search list.
|
||
|
||
Arguments:
|
||
|
||
pSearchList -- ptr to search list being built
|
||
|
||
pszName -- name to add to search list
|
||
|
||
Flag -- flag value
|
||
|
||
Return Value:
|
||
|
||
None. Name is added to search list, unless memory alloc failure.
|
||
|
||
--*/
|
||
{
|
||
DWORD count = pSearchList->NameCount;
|
||
PSTR pallocName;
|
||
|
||
DNSDBG( TRACE, ( "Search_AddName()\n" ));
|
||
|
||
//
|
||
// ignore name is already in list
|
||
// ignore if at list max
|
||
//
|
||
|
||
if ( SearchList_ContainsName(
|
||
pSearchList,
|
||
pszName )
|
||
||
|
||
count >= pSearchList->MaxNameCount )
|
||
{
|
||
return;
|
||
}
|
||
|
||
// copy name and put in list
|
||
|
||
pallocName = Dns_CreateStringCopy( pszName, 0 );
|
||
if ( !pallocName )
|
||
{
|
||
return;
|
||
}
|
||
pSearchList->SearchNameArray[count].pszName = pallocName;
|
||
|
||
//
|
||
// set flag -- but first flag always zero (normal timeouts)
|
||
// this protects against no PDN situation where use adapter
|
||
// name as PDN;
|
||
|
||
if ( count == 0 )
|
||
{
|
||
Flag = 0;
|
||
}
|
||
pSearchList->SearchNameArray[count].Flags = Flag;
|
||
pSearchList->NameCount = ++count;
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
SearchList_Parse(
|
||
IN OUT PSEARCH_LIST pSearchList,
|
||
IN PSTR pszList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parse registry search list string into SEARCH_LIST structure.
|
||
|
||
Arguments:
|
||
|
||
pSearchList -- search list array
|
||
|
||
pszList -- registry list of search names;
|
||
names are comma or white space separated
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
register PCHAR pch = pszList;
|
||
CHAR ch;
|
||
PUCHAR pnameStart;
|
||
DWORD countNames = pSearchList->NameCount;
|
||
|
||
DNSDBG( NETINFO, (
|
||
"SearchList_Parse( %p, %s )\n",
|
||
pSearchList,
|
||
pszList ));
|
||
|
||
//
|
||
// extract each domain name string in buffer,
|
||
// and add to search list array
|
||
//
|
||
|
||
while( ch = *pch && countNames < DNS_MAX_SEARCH_LIST_ENTRIES )
|
||
{
|
||
// skip leading whitespace, find start of domain name string
|
||
|
||
while( ch == ' ' || ch == '\t' || ch == ',' )
|
||
{
|
||
ch = *++pch;
|
||
}
|
||
if ( ch == 0 )
|
||
{
|
||
break;
|
||
}
|
||
pnameStart = pch;
|
||
|
||
//
|
||
// find end of string and NULL terminate
|
||
//
|
||
|
||
ch = *pch;
|
||
while( ch != ' ' && ch != '\t' && ch != '\0' && ch != ',' )
|
||
{
|
||
ch = *++pch;
|
||
}
|
||
*pch = '\0';
|
||
|
||
//
|
||
// end of buffer?
|
||
//
|
||
|
||
if ( pch == pnameStart )
|
||
{
|
||
break;
|
||
}
|
||
|
||
//
|
||
// whack any trailing dot on name
|
||
//
|
||
|
||
pch--;
|
||
if ( *pch == '.' )
|
||
{
|
||
*pch = '\0';
|
||
}
|
||
pch++;
|
||
|
||
//
|
||
// make copy of the name
|
||
//
|
||
|
||
pSearchList->SearchNameArray[ countNames ].pszName =
|
||
Dns_CreateStringCopy( pnameStart, 0 );
|
||
|
||
if ( pSearchList->SearchNameArray[ countNames ].pszName )
|
||
{
|
||
pSearchList->SearchNameArray[ countNames ].Flags = 0;
|
||
countNames++;
|
||
}
|
||
|
||
// if more continue
|
||
|
||
if ( ch != 0 )
|
||
{
|
||
pch++;
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
|
||
// reset name count
|
||
|
||
pSearchList->NameCount = countNames;
|
||
|
||
return( ERROR_SUCCESS );
|
||
}
|
||
|
||
|
||
|
||
PSEARCH_LIST
|
||
SearchList_Build(
|
||
IN PSTR pszPrimaryDomainName,
|
||
IN PREG_SESSION pRegSession,
|
||
IN HKEY hKey,
|
||
IN OUT PDNS_NETINFO pNetInfo,
|
||
IN BOOL fUseDomainNameDevolution,
|
||
IN BOOL fUseDotLocalDomain
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build search list.
|
||
|
||
Arguments:
|
||
|
||
pszPrimaryDomainName -- primary domain name
|
||
|
||
pRegSession -- registry session
|
||
|
||
hKey -- registry key
|
||
|
||
Return Value:
|
||
|
||
Ptr to search list.
|
||
NULL on error or no search list.
|
||
|
||
--*/
|
||
{
|
||
PSEARCH_LIST ptempList;
|
||
PSTR pregList = NULL;
|
||
DWORD status;
|
||
|
||
|
||
DNSDBG( TRACE, ( "Search_ListBuild()\n" ));
|
||
|
||
ASSERT( pRegSession || hKey );
|
||
|
||
//
|
||
// create search list using PDN
|
||
//
|
||
|
||
ptempList = SearchList_Alloc(
|
||
DNS_MAX_SEARCH_LIST_ENTRIES,
|
||
pszPrimaryDomainName );
|
||
if ( !ptempList )
|
||
{
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// read search list from registry
|
||
//
|
||
|
||
ptempList->NameCount = 0;
|
||
|
||
status = Reg_GetValue(
|
||
pRegSession,
|
||
hKey,
|
||
RegIdSearchList,
|
||
REGTYPE_SEARCH_LIST,
|
||
(PBYTE*) &pregList
|
||
);
|
||
|
||
if ( status == ERROR_SUCCESS )
|
||
{
|
||
ASSERT( pregList != NULL );
|
||
|
||
SearchList_Parse(
|
||
ptempList,
|
||
pregList );
|
||
|
||
FREE_HEAP( pregList );
|
||
}
|
||
|
||
//
|
||
// if no registry search list -- build one
|
||
//
|
||
// DCR: eliminate autobuilt search list
|
||
//
|
||
|
||
if ( ! ptempList->NameCount )
|
||
{
|
||
PSTR pname;
|
||
DWORD countNames = 0;
|
||
DWORD iter;
|
||
|
||
//
|
||
// use PDN in first search list slot
|
||
//
|
||
|
||
if ( pszPrimaryDomainName )
|
||
{
|
||
SearchList_AddName(
|
||
ptempList,
|
||
pszPrimaryDomainName,
|
||
0 );
|
||
}
|
||
|
||
//
|
||
// add devolved PDN if have NameDevolution
|
||
//
|
||
|
||
if ( ptempList->pszDomainOrZoneName &&
|
||
fUseDomainNameDevolution )
|
||
{
|
||
PSTR ptoken = ptempList->pszDomainOrZoneName;
|
||
|
||
ptoken = strchr( ptoken, '.' );
|
||
|
||
while ( ptoken )
|
||
{
|
||
ptoken += 1;
|
||
|
||
if ( strchr( ptoken, '.' ) )
|
||
{
|
||
SearchList_AddName(
|
||
ptempList,
|
||
ptoken,
|
||
DNS_QUERY_USE_QUICK_TIMEOUTS );
|
||
|
||
ptoken = strchr( ptoken, '.' );
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// add ".local" to search list if enabled
|
||
//
|
||
|
||
if ( fUseDotLocalDomain )
|
||
{
|
||
SearchList_AddName(
|
||
ptempList,
|
||
MULTICAST_DNS_LOCAL_DOMAIN,
|
||
DNS_QUERY_MULTICAST_ONLY
|
||
);
|
||
}
|
||
|
||
// indicate this is dummy search list
|
||
|
||
if ( pNetInfo )
|
||
{
|
||
pNetInfo->InfoFlags |= DNS_FLAG_DUMMY_SEARCH_LIST;
|
||
}
|
||
}
|
||
|
||
return ptempList;
|
||
}
|
||
|
||
|
||
|
||
PSTR
|
||
SearchList_GetNextName(
|
||
IN OUT PSEARCH_LIST pSearchList,
|
||
IN BOOL fReset,
|
||
OUT PDWORD pdwSuffixFlags OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the next name from the search list.
|
||
|
||
Arguments:
|
||
|
||
pSearchList -- search list
|
||
|
||
fReset -- TRUE to reset to beginning of search list
|
||
|
||
pdwSuffixFlags -- flags associate with using this suffix
|
||
|
||
Return Value:
|
||
|
||
Ptr to the next search name. Note, this is a pointer
|
||
to a name in the search list NOT an allocation. Search
|
||
list structure must stay valid during use.
|
||
|
||
NULL when out of search names.
|
||
|
||
--*/
|
||
{
|
||
DWORD flag = 0;
|
||
PSTR pname = NULL;
|
||
DWORD index;
|
||
|
||
|
||
DNSDBG( TRACE, ( "SearchList_GetNextName()\n" ));
|
||
|
||
// no list
|
||
|
||
if ( !pSearchList )
|
||
{
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// reset?
|
||
//
|
||
|
||
if ( fReset )
|
||
{
|
||
pSearchList->CurrentNameIndex = 0;
|
||
}
|
||
|
||
//
|
||
// if valid name -- retrieve it
|
||
//
|
||
|
||
index = pSearchList->CurrentNameIndex;
|
||
|
||
if ( index < pSearchList->NameCount )
|
||
{
|
||
pname = pSearchList->SearchNameArray[index].pszName;
|
||
flag = pSearchList->SearchNameArray[index].Flags;
|
||
pSearchList->CurrentNameIndex = ++index;
|
||
}
|
||
|
||
Done:
|
||
|
||
if ( pdwSuffixFlags )
|
||
{
|
||
*pdwSuffixFlags = flag;
|
||
}
|
||
return pname;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Net info routines
|
||
//
|
||
|
||
PDNS_NETINFO
|
||
NetInfo_Alloc(
|
||
IN DWORD AdapterCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocate network info.
|
||
|
||
Arguments:
|
||
|
||
AdapterCount -- count of net adapters info will hold
|
||
|
||
Return Value:
|
||
|
||
Ptr to uninitialized DNS network info, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO pnetInfo;
|
||
DWORD length;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_Alloc()\n" ));
|
||
|
||
//
|
||
// alloc
|
||
// - zero to avoid garbage on early free
|
||
//
|
||
|
||
length = sizeof(DNS_NETINFO)
|
||
- sizeof(PDNS_ADAPTER)
|
||
+ (sizeof(PDNS_ADAPTER) * AdapterCount);
|
||
|
||
pnetInfo = (PDNS_NETINFO) ALLOCATE_HEAP_ZERO( length );
|
||
if ( ! pnetInfo )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
pnetInfo->MaxAdapterCount = AdapterCount;
|
||
|
||
return( pnetInfo );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NetInfo_Free(
|
||
IN OUT PDNS_NETINFO pNetInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free DNS_NETINFO structure.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- ptr to netinfo to free
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DWORD i;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_Free( %p )\n", pNetInfo ));
|
||
|
||
if ( ! pNetInfo )
|
||
{
|
||
return;
|
||
}
|
||
IF_DNSDBG( OFF )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"Network Info before free: ",
|
||
pNetInfo );
|
||
}
|
||
|
||
//
|
||
// free
|
||
// - search list
|
||
// - domain name
|
||
// - all the adapter info blobs
|
||
//
|
||
|
||
SearchList_Free( pNetInfo->pSearchList );
|
||
|
||
if ( pNetInfo->pszDomainName )
|
||
{
|
||
FREE_HEAP( pNetInfo->pszDomainName );
|
||
}
|
||
if ( pNetInfo->pszHostName )
|
||
{
|
||
FREE_HEAP( pNetInfo->pszHostName );
|
||
}
|
||
|
||
for ( i=0; i < pNetInfo->AdapterCount; i++ )
|
||
{
|
||
AdapterInfo_Free( pNetInfo->AdapterArray[i] );
|
||
}
|
||
|
||
FREE_HEAP( pNetInfo );
|
||
}
|
||
|
||
|
||
|
||
PDNS_NETINFO
|
||
NetInfo_Copy(
|
||
IN PDNS_NETINFO pNetInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of DNS Network info.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- DNS Network info to copy
|
||
|
||
Return Value:
|
||
|
||
Ptr to DNS Network info copy, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO pcopy;
|
||
DWORD adapterCount;
|
||
DWORD i;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_Copy( %p )\n", pNetInfo ));
|
||
|
||
if ( ! pNetInfo )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
IF_DNSDBG( NETINFO2 )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"Netinfo to copy: ",
|
||
pNetInfo );
|
||
}
|
||
|
||
//
|
||
// create network info struct of desired size
|
||
//
|
||
|
||
pcopy = NetInfo_Alloc( pNetInfo->AdapterCount );
|
||
if ( ! pcopy )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// copy flat fields
|
||
// - must reset MaxAdapterCount to actual allocation
|
||
// - AdapterCount reset below
|
||
|
||
RtlCopyMemory(
|
||
pcopy,
|
||
pNetInfo,
|
||
(PBYTE) &pcopy->AdapterArray[0] - (PBYTE)pcopy );
|
||
|
||
pcopy->MaxAdapterCount = pNetInfo->AdapterCount;
|
||
|
||
//
|
||
// copy subcomponents
|
||
// - domain name
|
||
// - search list
|
||
// - adapter info for each adapter
|
||
//
|
||
|
||
pcopy->pszDomainName = Dns_CreateStringCopy(
|
||
pNetInfo->pszDomainName,
|
||
0 );
|
||
pcopy->pszHostName = Dns_CreateStringCopy(
|
||
pNetInfo->pszHostName,
|
||
0 );
|
||
|
||
pcopy->pSearchList = SearchList_Copy( pNetInfo->pSearchList );
|
||
|
||
adapterCount = 0;
|
||
for ( i=0; i < pNetInfo->AdapterCount; i++ )
|
||
{
|
||
PDNS_ADAPTER pnew = AdapterInfo_Copy( pNetInfo->AdapterArray[i] );
|
||
if ( pnew )
|
||
{
|
||
pcopy->AdapterArray[ adapterCount++ ] = pnew;
|
||
}
|
||
}
|
||
pcopy->AdapterCount = adapterCount;
|
||
|
||
IF_DNSDBG( NETINFO2 )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"Netinfo copy: ",
|
||
pcopy );
|
||
}
|
||
return pcopy;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
NetInfo_AddAdapter(
|
||
IN OUT PDNS_NETINFO pNetInfo,
|
||
IN PDNS_ADAPTER pAdapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Add adapter info to network info.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- netinfo to add to
|
||
|
||
pAdapter -- actual adapter to add (it is plugged in NOT copied)
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful.
|
||
FALSE if list full.
|
||
|
||
--*/
|
||
{
|
||
DWORD i;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_AddAdapter( %p )\n", pNetInfo ));
|
||
|
||
//
|
||
// find first open slot
|
||
//
|
||
|
||
for ( i = 0; i < pNetInfo->MaxAdapterCount; i++ )
|
||
{
|
||
if ( ! pNetInfo->AdapterArray[i] )
|
||
{
|
||
pNetInfo->AdapterArray[i] = pAdapter;
|
||
pNetInfo->AdapterCount++;
|
||
return( TRUE );
|
||
}
|
||
}
|
||
|
||
IF_DNSDBG( NETINFO )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"Network info failed adapter add: ",
|
||
pNetInfo );
|
||
}
|
||
return( FALSE );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NetInfo_Clean(
|
||
IN OUT PDNS_NETINFO pNetInfo,
|
||
IN DWORD ClearLevel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clean network info.
|
||
|
||
Removes all query specific info and restores to
|
||
state that is "fresh" for next query.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- DNS network info
|
||
|
||
ClearLevel -- level of runtime flag cleaning
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DWORD i;
|
||
|
||
DNSDBG( TRACE, (
|
||
"Enter NetInfo_Clean( %p, %08x )\n",
|
||
pNetInfo,
|
||
ClearLevel ));
|
||
|
||
IF_DNSDBG( NETINFO2 )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"Cleaning network info:",
|
||
pNetInfo
|
||
);
|
||
}
|
||
|
||
//
|
||
// clean up info
|
||
// - clear status fields
|
||
// - clear RunFlags
|
||
// - clear temp bits on InfoFlags
|
||
//
|
||
// note, runtime flags are wiped depending on level
|
||
// specified in call
|
||
// - all (includes disabled\timedout adapter info)
|
||
// - query (all query info)
|
||
// - name (all info for single name query)
|
||
//
|
||
// finally we set NETINFO_PREPARED flag so that we can
|
||
// can check for and do this initialization in the send
|
||
// code if not previously done;
|
||
//
|
||
// in the standard query path we can
|
||
// - do this init
|
||
// - disallow adapters based on query name
|
||
// - send without the info getting wiped
|
||
//
|
||
// in other send paths
|
||
// - send checks that NETINFO_PREPARED is not set
|
||
// - does basic init
|
||
//
|
||
|
||
pNetInfo->ReturnFlags &= ClearLevel;
|
||
pNetInfo->ReturnFlags |= RUN_FLAG_NETINFO_PREPARED;
|
||
|
||
for( i=0; i<pNetInfo->AdapterCount; i++ )
|
||
{
|
||
PDNS_ADAPTER padapter;
|
||
DWORD j;
|
||
|
||
padapter = pNetInfo->AdapterArray[i];
|
||
|
||
padapter->Status = 0;
|
||
padapter->RunFlags &= ClearLevel;
|
||
padapter->ServerIndex = EMPTY_SERVER_INDEX;
|
||
|
||
// clear server status fields
|
||
|
||
for ( j=0; j<padapter->ServerCount; j++ )
|
||
{
|
||
padapter->ServerArray[j].Status = DNSSS_NEW;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NetInfo_ResetServerPriorities(
|
||
IN OUT PDNS_NETINFO pNetInfo,
|
||
IN BOOL fLocalDnsOnly
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Resets the DNS server priority values for the DNS servers.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- pointer to a DNS network info structure.
|
||
|
||
fLocalDnsOnly - TRUE to reset priority ONLY on local DNS servers
|
||
Note that this requires that the network info contain the IP address
|
||
list for each adapter so that the IP address list can be compared
|
||
to the DNS server list.
|
||
|
||
Return Value:
|
||
|
||
Nothing
|
||
|
||
--*/
|
||
{
|
||
DWORD i;
|
||
DWORD j;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_ResetServerPriorities( %p )\n", pNetInfo ));
|
||
|
||
if ( ! pNetInfo )
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// reset priorities on server
|
||
// when
|
||
// - not do local only OR
|
||
// - server IP matches one of adapter IPs
|
||
//
|
||
// DCR: local DNS check needs IP6 fixups
|
||
//
|
||
|
||
for ( i = 0; i < pNetInfo->AdapterCount; i++ )
|
||
{
|
||
PDNS_ADAPTER padapter = pNetInfo->AdapterArray[i];
|
||
|
||
for ( j=0; j < padapter->ServerCount; j++ )
|
||
{
|
||
PDNS_SERVER_INFO pserver = &padapter->ServerArray[j];
|
||
|
||
if ( !fLocalDnsOnly ||
|
||
Dns_IsAddressInIpArray(
|
||
padapter->pAdapterIPAddresses,
|
||
pserver->IpAddress ) ||
|
||
pserver->IpAddress == DNS_NET_ORDER_LOOPBACK )
|
||
{
|
||
pserver->Priority = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
PIP_ARRAY
|
||
NetInfo_ConvertToIpArray(
|
||
IN PDNS_NETINFO pNetInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create IP array of DNS servers from network info.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- DNS net adapter list to convert
|
||
|
||
Return Value:
|
||
|
||
Ptr to IP array, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PIP_ARRAY parray;
|
||
DWORD i;
|
||
DWORD j;
|
||
DWORD countServers = 0;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_ConvertToIpArray( %p )\n", pNetInfo ));
|
||
|
||
if ( ! pNetInfo )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// count up all the servers in list, create IP array of desired size
|
||
//
|
||
|
||
for ( i = 0;
|
||
i < pNetInfo->AdapterCount;
|
||
i++ )
|
||
{
|
||
countServers += pNetInfo->AdapterArray[i]->ServerCount;
|
||
}
|
||
parray = Dns_CreateIpArray( countServers );
|
||
if ( !parray )
|
||
{
|
||
SetLastError( DNS_ERROR_NO_MEMORY );
|
||
return( NULL );
|
||
}
|
||
DNS_ASSERT( parray->AddrCount == countServers );
|
||
|
||
//
|
||
// read all servers into IP array
|
||
//
|
||
|
||
countServers = 0;
|
||
for ( i = 0;
|
||
i < pNetInfo->AdapterCount;
|
||
i++ )
|
||
{
|
||
PDNS_ADAPTER padapter = pNetInfo->AdapterArray[i];
|
||
|
||
for ( j = 0;
|
||
j < padapter->ServerCount;
|
||
j++ )
|
||
{
|
||
parray->AddrArray[ countServers++ ]
|
||
= padapter->ServerArray[j].IpAddress;
|
||
}
|
||
}
|
||
|
||
DNS_ASSERT( parray->AddrCount == countServers );
|
||
return( parray );
|
||
}
|
||
|
||
|
||
|
||
PDNS_NETINFO
|
||
NetInfo_CreateForUpdate(
|
||
IN PSTR pszZone,
|
||
IN PSTR pszServerName,
|
||
IN PIP_ARRAY pServerArray,
|
||
IN DWORD dwFlags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create network info suitable for update.
|
||
|
||
Arguments:
|
||
|
||
pszZone -- target zone name
|
||
|
||
pszServerName -- target server name
|
||
|
||
pServerArray -- IP array with target server IP
|
||
|
||
dwFlags -- flags
|
||
|
||
|
||
Return Value:
|
||
|
||
Ptr to resulting update compatible network info.
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PSEARCH_LIST psearchList;
|
||
PDNS_ADAPTER padapter;
|
||
PDNS_NETINFO pnetworkInfo;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_BuildForUpdate()\n" ));
|
||
|
||
//
|
||
// allocate
|
||
//
|
||
|
||
pnetworkInfo = NetInfo_Alloc( 1 );
|
||
if ( !pnetworkInfo )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// make search list from desired zone
|
||
//
|
||
|
||
if ( pszZone )
|
||
{
|
||
psearchList = SearchList_Alloc( 0, pszZone );
|
||
if ( ! psearchList )
|
||
{
|
||
goto Fail;
|
||
}
|
||
pnetworkInfo->pSearchList = psearchList;
|
||
}
|
||
|
||
//
|
||
// convert IP array and server name to server list
|
||
//
|
||
|
||
padapter = AdapterInfo_CreateFromIpArray(
|
||
pServerArray,
|
||
dwFlags,
|
||
pszServerName,
|
||
NULL );
|
||
if ( ! padapter )
|
||
{
|
||
goto Fail;
|
||
}
|
||
pnetworkInfo->AdapterArray[0] = padapter;
|
||
pnetworkInfo->AdapterCount = 1;
|
||
|
||
IF_DNSDBG( NETINFO2 )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"Update network info is: ",
|
||
pnetworkInfo );
|
||
}
|
||
return pnetworkInfo;
|
||
|
||
Fail:
|
||
|
||
NetInfo_Free( pnetworkInfo );
|
||
return NULL;
|
||
}
|
||
|
||
|
||
|
||
PSTR
|
||
NetInfo_UpdateZoneName(
|
||
IN PDNS_NETINFO pNetInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieve update zone name.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- blob to check
|
||
|
||
Return Value:
|
||
|
||
Ptr to update zone name.
|
||
NULL on error.
|
||
|
||
--*/
|
||
{
|
||
return pNetInfo->pSearchList->pszDomainOrZoneName;
|
||
|
||
// return pNetInfo->AdapterArray[0]-pszAdapterGuidName;
|
||
// return pNetInfo->pszDomainName;
|
||
}
|
||
|
||
|
||
|
||
PSTR
|
||
NetInfo_UpdateServerName(
|
||
IN PDNS_NETINFO pNetInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieve update servere name.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- blob to check
|
||
|
||
Return Value:
|
||
|
||
Ptr to update zone name.
|
||
NULL on error.
|
||
|
||
--*/
|
||
{
|
||
return pNetInfo->AdapterArray[0]->pszAdapterDomain;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
NetInfo_IsForUpdate(
|
||
IN PDNS_NETINFO pNetInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check if network info blob if "update capable".
|
||
|
||
This means whether it is the result of a FAZ and
|
||
can be used to send updates.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- blob to check
|
||
|
||
Return Value:
|
||
|
||
TRUE if update network info.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, ( "NetInfo_IsForUpdate()\n" ));
|
||
|
||
return ( pNetInfo &&
|
||
pNetInfo->pSearchList &&
|
||
pNetInfo->pSearchList->pszDomainOrZoneName &&
|
||
pNetInfo->AdapterCount == 1 &&
|
||
pNetInfo->AdapterArray[0] );
|
||
}
|
||
|
||
|
||
|
||
PDNS_NETINFO
|
||
NetInfo_CreateFromIpArray(
|
||
IN PIP4_ARRAY pDnsServers,
|
||
IN IP4_ADDRESS ServerIp,
|
||
IN BOOL fSearchInfo,
|
||
IN PDNS_NETINFO pNetInfo OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create network info given DNS server list.
|
||
|
||
Arguments:
|
||
|
||
pDnsServers -- IP array of DNS servers
|
||
|
||
ServerIp -- single IP in list
|
||
|
||
fSearchInfo -- TRUE if need search info
|
||
|
||
pNetInfo -- current network info blob to copy search info
|
||
from; this field is only relevant if fSearchInfo is TRUE
|
||
|
||
Return Value:
|
||
|
||
Ptr to resulting network info.
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO pnetInfo;
|
||
IP4_ARRAY ipArray;
|
||
PIP4_ARRAY parray = pDnsServers;
|
||
PSEARCH_LIST psearchList;
|
||
PSTR pdomainName;
|
||
DWORD flags = 0;
|
||
|
||
//
|
||
// DCR: eliminate search list form this routine
|
||
// i believe this routine is only used for query of
|
||
// FQDNs (usually in update) and doesn't require
|
||
// any default search info
|
||
//
|
||
// DCR: possibly combine with "BuildForUpdate" routine
|
||
// where search info included tacks this on
|
||
//
|
||
|
||
//
|
||
// if given single IP, ONLY use it
|
||
//
|
||
|
||
if ( ServerIp )
|
||
{
|
||
ipArray.AddrCount = 1;
|
||
ipArray.AddrArray[0] = ServerIp;
|
||
parray = &ipArray;
|
||
}
|
||
|
||
//
|
||
// convert server IPs into network info blob
|
||
// - simply use update function above to avoid duplicate code
|
||
//
|
||
|
||
pnetInfo = NetInfo_CreateForUpdate(
|
||
NULL, // no zone
|
||
NULL, // no server name
|
||
parray,
|
||
0 // no flags
|
||
);
|
||
if ( !pnetInfo )
|
||
{
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// get search list and primary domain info
|
||
// - copy from passed in network info
|
||
// OR
|
||
// - cut directly out of new netinfo
|
||
//
|
||
|
||
if ( fSearchInfo )
|
||
{
|
||
if ( pNetInfo )
|
||
{
|
||
flags = pNetInfo->InfoFlags;
|
||
psearchList = SearchList_Copy( pNetInfo->pSearchList );
|
||
pdomainName = Dns_CreateStringCopy(
|
||
pNetInfo->pszDomainName,
|
||
0 );
|
||
|
||
}
|
||
else
|
||
{
|
||
PDNS_NETINFO ptempNetInfo = GetNetworkInfo();
|
||
|
||
if ( ptempNetInfo )
|
||
{
|
||
flags = ptempNetInfo->InfoFlags;
|
||
psearchList = ptempNetInfo->pSearchList;
|
||
pdomainName = ptempNetInfo->pszDomainName;
|
||
|
||
ptempNetInfo->pSearchList = NULL;
|
||
ptempNetInfo->pszDomainName = NULL;
|
||
NetInfo_Free( ptempNetInfo );
|
||
}
|
||
else
|
||
{
|
||
psearchList = NULL;
|
||
pdomainName = NULL;
|
||
}
|
||
}
|
||
|
||
// plug search info into new netinfo blob
|
||
|
||
pnetInfo->pSearchList = psearchList;
|
||
pnetInfo->pszDomainName = pdomainName;
|
||
pnetInfo->InfoFlags |= (flags & DNS_FLAG_DUMMY_SEARCH_LIST);
|
||
}
|
||
|
||
return( pnetInfo );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// DNS server reachability routines
|
||
//
|
||
// These are used to build netinfo that has unreachable DNS
|
||
// servers screened out of the list.
|
||
//
|
||
|
||
BOOL
|
||
IsReachableDnsServer(
|
||
IN PDNS_NETINFO pNetInfo,
|
||
IN PDNS_ADAPTER pAdapter,
|
||
IN IP4_ADDRESS Ip4Addr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine if DNS server is reachable.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- network info blob
|
||
|
||
pAdapter -- struct with list of DNS servers
|
||
|
||
Ip4Addr -- DNS server address to test for reachability
|
||
|
||
Return Value:
|
||
|
||
TRUE if DNS server is reachable.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
DWORD interfaceIndex;
|
||
DNS_STATUS status;
|
||
|
||
DNSDBG( NETINFO, (
|
||
"Enter IsReachableDnsServer( %p, %p, %08x )\n",
|
||
pNetInfo,
|
||
pAdapter,
|
||
Ip4Addr ));
|
||
|
||
DNS_ASSERT( pNetInfo && pAdapter );
|
||
|
||
//
|
||
// DCR: should do reachablity once on netinfo build
|
||
//
|
||
// DCR: reachability test can be smarter
|
||
// - reachable if same subnet as adapter IP
|
||
// question: multiple IPs?
|
||
// - reachable if same subnet as previous reachable IP
|
||
// question: can tell if same subnet?
|
||
//
|
||
// DCR: reachability on multi-homed connected
|
||
// - if send on another interface, does that interface
|
||
// "seem" to be connected
|
||
// probably see if
|
||
// - same subnet as this inteface
|
||
// question: multiple IPs
|
||
// - or share DNS servers in common
|
||
// question: just let server go, this doesn't work if
|
||
// the name is not the same
|
||
//
|
||
|
||
|
||
//
|
||
// if only one interface, assume reachability
|
||
//
|
||
|
||
if ( pNetInfo->AdapterCount <= 1 )
|
||
{
|
||
DNSDBG( SEND, (
|
||
"One interface, assume reachability!\n" ));
|
||
return( TRUE );
|
||
}
|
||
|
||
//
|
||
// check if server IP is reachable on its interface
|
||
//
|
||
|
||
status = IpHelp_GetBestInterface(
|
||
Ip4Addr,
|
||
& interfaceIndex );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
DNSDBG( ANY, (
|
||
"GetBestInterface() failed! %d\n",
|
||
status ));
|
||
return( TRUE );
|
||
}
|
||
|
||
if ( pAdapter->InterfaceIndex != interfaceIndex )
|
||
{
|
||
DNSDBG( NETINFO, (
|
||
"IP %s on interface %d is unreachable!\n"
|
||
"\tsend would be on interface %d\n",
|
||
IP_STRING( Ip4Addr ),
|
||
pAdapter->InterfaceIndex,
|
||
interfaceIndex ));
|
||
|
||
return( FALSE );
|
||
}
|
||
|
||
return( TRUE );
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
IsDnsReachableOnAlternateInterface(
|
||
IN PDNS_NETINFO pNetInfo,
|
||
IN DWORD InterfaceIndex,
|
||
IN IP4_ADDRESS Ip4Addr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine if IP address is reachable on adapter.
|
||
|
||
This function determines whether DNS IP can be reached
|
||
on the interface that the stack indicates, when that
|
||
interface is NOT the one containing the DNS server.
|
||
|
||
We need this so we catch the multi-homed CONNECTED cases
|
||
where a DNS server is still reachable even though the
|
||
interface the stack will send on is NOT the interface for
|
||
the DNS server.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- network info blob
|
||
|
||
Interface -- interface stack will send to IP on
|
||
|
||
Ip4Addr -- DNS server address to test for reachability
|
||
|
||
Return Value:
|
||
|
||
TRUE if DNS server is reachable.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADAPTER padapter;
|
||
DWORD i;
|
||
PIP4_ARRAY pipArray;
|
||
PIP4_ARRAY psubnetArray;
|
||
DWORD ipCount;
|
||
|
||
DNSDBG( NETINFO, (
|
||
"Enter IsDnsReachableOnAlternateInterface( %p, %d, %08x )\n",
|
||
pNetInfo,
|
||
InterfaceIndex,
|
||
Ip4Addr ));
|
||
|
||
//
|
||
// find DNS adapter for interface
|
||
//
|
||
|
||
for( i=0; i<pNetInfo->AdapterCount; i++ )
|
||
{
|
||
padapter = pNetInfo->AdapterArray[i];
|
||
|
||
if ( padapter->InterfaceIndex != InterfaceIndex )
|
||
{
|
||
padapter = NULL;
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
|
||
if ( !padapter )
|
||
{
|
||
DNSDBG( ANY, (
|
||
"WARNING: indicated send inteface %d NOT in netinfo!\n",
|
||
InterfaceIndex ));
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// two success conditions:
|
||
// 1) our IP matches IP of DNS server for this interface
|
||
// 2) our IP is on subnet of IP on this interface
|
||
//
|
||
// if either of these is TRUE then either
|
||
// - there is misconfiguration (not our problem)
|
||
// OR
|
||
// - these interfaces are connected and we can safely send on
|
||
// them
|
||
//
|
||
// DCR: it would be cool to save the default gateway for the interface
|
||
// and use it?
|
||
|
||
for ( i=0; i<padapter->ServerCount; i++ )
|
||
{
|
||
if ( Ip4Addr == padapter->ServerArray[i].IpAddress )
|
||
{
|
||
DNSDBG( NETINFO, (
|
||
"DNS server %08x also DNS server on send interface %d\n",
|
||
Ip4Addr,
|
||
InterfaceIndex ));
|
||
return( TRUE );
|
||
}
|
||
}
|
||
|
||
// test for subnet match
|
||
|
||
pipArray = padapter->pAdapterIPAddresses;
|
||
psubnetArray = padapter->pAdapterIPSubnetMasks;
|
||
|
||
if ( !pipArray ||
|
||
!psubnetArray ||
|
||
(ipCount = pipArray->AddrCount) != psubnetArray->AddrCount )
|
||
{
|
||
DNSDBG( ANY, ( "WARNING: missing or invalid interface IP\\subnet info!\n" ));
|
||
DNS_ASSERT( FALSE );
|
||
return( FALSE );
|
||
}
|
||
|
||
for ( i=0; i<ipCount; i++ )
|
||
{
|
||
IP4_ADDRESS subnet = psubnetArray->AddrArray[i];
|
||
|
||
if ( (subnet & Ip4Addr) == (subnet & pipArray->AddrArray[i]) )
|
||
{
|
||
DNSDBG( NETINFO, (
|
||
"DNS server %08x on subnet of IP for send interface %d\n"
|
||
"\tip = %08x, subnet = %08x\n",
|
||
Ip4Addr,
|
||
InterfaceIndex,
|
||
pipArray->AddrArray[i],
|
||
subnet ));
|
||
|
||
return( TRUE );
|
||
}
|
||
}
|
||
|
||
return( FALSE );
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
StrikeOutUnreachableDnsServers(
|
||
IN OUT PDNS_NETINFO pNetInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Eliminate unreachable DNS servers from the list.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- DNS netinfo to fix up
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status;
|
||
DWORD validServers;
|
||
PDNS_ADAPTER padapter;
|
||
DWORD adapterIfIndex;
|
||
DWORD serverIfIndex;
|
||
DWORD i;
|
||
DWORD j;
|
||
|
||
|
||
DNSDBG( NETINFO, (
|
||
"Enter StrikeOutUnreachableDnsServers( %p )\n",
|
||
pNetInfo ));
|
||
|
||
DNS_ASSERT( pNetInfo );
|
||
|
||
//
|
||
// if only one interface, assume reachability
|
||
//
|
||
|
||
if ( pNetInfo->AdapterCount <= 1 )
|
||
{
|
||
DNSDBG( NETINFO, (
|
||
"One interface, assume reachability!\n" ));
|
||
return( TRUE );
|
||
}
|
||
|
||
//
|
||
// loop through adapters
|
||
//
|
||
|
||
for( i=0; i<pNetInfo->AdapterCount; i++ )
|
||
{
|
||
padapter = pNetInfo->AdapterArray[i];
|
||
|
||
// ignore this adapter because there are no DNS
|
||
// servers configured?
|
||
|
||
if ( padapter->InfoFlags & DNS_FLAG_IGNORE_ADAPTER )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// test all adapter's DNS servers for reachability
|
||
//
|
||
// note: currently save no server specific reachability,
|
||
// so if any server reachable, proceed;
|
||
// also if iphelp fails just assume reachability and proceed,
|
||
// better timeouts then not reaching server we can reach
|
||
//
|
||
|
||
adapterIfIndex = padapter->InterfaceIndex;
|
||
validServers = 0;
|
||
|
||
for ( j=0; j<padapter->ServerCount; j++ )
|
||
{
|
||
IP4_ADDRESS dnsIp = padapter->ServerArray[j].IpAddress;
|
||
|
||
status = IpHelp_GetBestInterface(
|
||
dnsIp,
|
||
& serverIfIndex );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
DNSDBG( ANY, (
|
||
"GetBestInterface() failed! %d\n",
|
||
status ));
|
||
validServers++;
|
||
break;
|
||
//continue;
|
||
}
|
||
|
||
// server is reachable
|
||
// - queried on its adapter?
|
||
// - reachable through loopback
|
||
//
|
||
// DCR: tag unreachable servers individually
|
||
|
||
if ( serverIfIndex == adapterIfIndex ||
|
||
serverIfIndex == 1 )
|
||
{
|
||
validServers++;
|
||
break;
|
||
//continue;
|
||
}
|
||
|
||
// server can be reached on query interface
|
||
|
||
if ( IsDnsReachableOnAlternateInterface(
|
||
pNetInfo,
|
||
serverIfIndex,
|
||
dnsIp ) )
|
||
{
|
||
validServers++;
|
||
break;
|
||
//continue;
|
||
}
|
||
}
|
||
|
||
//
|
||
// disable adapter if no servers found
|
||
//
|
||
// DCR: alternative to ignoring unreachable
|
||
// - tag as unreachable
|
||
// - don't send to it on first pass
|
||
// - don't continue name error on unreachable
|
||
// (it would count as "heard from" when send.c routine
|
||
// works back through)
|
||
|
||
if ( validServers == 0 )
|
||
{
|
||
padapter->InfoFlags |= (DNS_FLAG_IGNORE_ADAPTER |
|
||
DNS_FLAG_SERVERS_UNREACHABLE);
|
||
|
||
DNSDBG( NETINFO, (
|
||
"No reachable servers on interface %d\n"
|
||
"\tthis adapter (%p) ignored in DNS list!\n",
|
||
adapterIfIndex,
|
||
padapter ));
|
||
}
|
||
}
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Main netinfo build routine
|
||
//
|
||
|
||
PDNS_NETINFO
|
||
NetInfo_Build(
|
||
IN BOOL fGetIpAddrs
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build network info blob from registry.
|
||
|
||
This is the FULL recreate function.
|
||
|
||
Arguments:
|
||
|
||
fGetIpAddrs -- TRUE to include local IP addrs for each adapter
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
REG_SESSION regSession;
|
||
PREG_SESSION pregSession = NULL;
|
||
PDNS_NETINFO pnetInfo = NULL;
|
||
PDNS_ADAPTER padapter = NULL;
|
||
PIP_ARRAY ptempArray = NULL;
|
||
PIP_ARRAY plocalIpArray = NULL;
|
||
PIP_ARRAY psubnetIpArray = NULL;
|
||
PIP_ARRAY pserverIpArray = NULL;
|
||
DNS_STATUS status = NO_ERROR;
|
||
DWORD count;
|
||
PIP_ADAPTER_INFO pipAdapterInfo = NULL;
|
||
PIP_ADAPTER_INFO pipAdapter = NULL;
|
||
DWORD value;
|
||
PREG_GLOBAL_INFO pregInfo = NULL;
|
||
REG_GLOBAL_INFO regInfo;
|
||
REG_ADAPTER_INFO regAdapterInfo;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"NetInfo_Build( %d )\n",
|
||
fGetIpAddrs ));
|
||
|
||
//
|
||
// always get IP addresses
|
||
// - for multi-adapter need for routing
|
||
// - need for local lookups
|
||
// (might as well just include)
|
||
//
|
||
// DCR: could skip include when RPCing to client for
|
||
// query\update that does not require
|
||
//
|
||
|
||
fGetIpAddrs = TRUE;
|
||
|
||
//
|
||
// get adapters info from IP help
|
||
//
|
||
|
||
status = IpHelp_GetAdaptersInfo( &pipAdapterInfo );
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// open the registry
|
||
//
|
||
|
||
pregSession = ®Session;
|
||
|
||
status = Reg_OpenSession(
|
||
pregSession,
|
||
0,
|
||
0 );
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
status = DNS_ERROR_NO_DNS_SERVERS;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// read global registry info
|
||
//
|
||
|
||
pregInfo = ®Info;
|
||
|
||
status = Reg_ReadGlobalInfo(
|
||
pregSession,
|
||
pregInfo
|
||
);
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
status = DNS_ERROR_NO_DNS_SERVERS;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// build adapter information
|
||
//
|
||
|
||
// count up the active adapters
|
||
|
||
pipAdapter = pipAdapterInfo;
|
||
count = 0;
|
||
|
||
while ( pipAdapter )
|
||
{
|
||
count++;
|
||
pipAdapter = pipAdapter->Next;
|
||
}
|
||
|
||
//
|
||
// allocate net info blob
|
||
// allocate DNS server IP array
|
||
//
|
||
|
||
pnetInfo = NetInfo_Alloc( count );
|
||
|
||
ptempArray = Dns_CreateIpArray( DNS_MAX_IP_INTERFACE_COUNT );
|
||
|
||
if ( !pnetInfo ||
|
||
!ptempArray )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// set network info flags
|
||
//
|
||
// DCR: can use globals
|
||
//
|
||
|
||
if ( regInfo.fUseMulticast )
|
||
{
|
||
pnetInfo->InfoFlags |= DNS_FLAG_ALLOW_MULTICAST;
|
||
}
|
||
if ( regInfo.fUseMulticastOnNameError )
|
||
{
|
||
pnetInfo->InfoFlags |= DNS_FLAG_MULTICAST_ON_NAME_ERROR;
|
||
}
|
||
|
||
//
|
||
// loop through adapters -- build network info for each
|
||
//
|
||
|
||
pipAdapter = pipAdapterInfo;
|
||
|
||
while ( pipAdapter )
|
||
{
|
||
DWORD adapterFlags = 0;
|
||
PIP_PER_ADAPTER_INFO pperAdapterInfo = NULL;
|
||
PSTR padapterDomainName = NULL;
|
||
|
||
//
|
||
// read adapter registry info
|
||
//
|
||
|
||
status = Reg_ReadAdapterInfo(
|
||
pipAdapter->AdapterName,
|
||
pregSession,
|
||
& regInfo, // policy adapter info
|
||
& regAdapterInfo // receives reg info read
|
||
);
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Skip;
|
||
}
|
||
|
||
// translate results into flags
|
||
|
||
if ( regAdapterInfo.fRegistrationEnabled )
|
||
{
|
||
adapterFlags |= DNS_FLAG_REGISTER_IP_ADDRESSES;
|
||
}
|
||
if ( regAdapterInfo.fRegisterAdapterName )
|
||
{
|
||
adapterFlags |= DNS_FLAG_REGISTER_DOMAIN_NAME;
|
||
}
|
||
|
||
// use domain name?
|
||
// - if disable on per adapter basis, then it's dead
|
||
|
||
if ( regAdapterInfo.fQueryAdapterName )
|
||
{
|
||
padapterDomainName = regAdapterInfo.pszAdapterDomainName;
|
||
}
|
||
|
||
// set flag on DHCP adapters
|
||
|
||
if ( pipAdapter->DhcpEnabled )
|
||
{
|
||
adapterFlags |= DNS_FLAG_IS_DHCP_CFG_ADAPTER;
|
||
}
|
||
|
||
//
|
||
// get adapter's IP addresses
|
||
//
|
||
// DCR_FIX: why get IPs if aren't going to use
|
||
//
|
||
|
||
ptempArray->AddrCount = 0;
|
||
status = IpHelp_ParseIpAddressString(
|
||
ptempArray,
|
||
& pipAdapter->IpAddressList,
|
||
FALSE, // Get the ip address(es)
|
||
TRUE // Reverse the order because
|
||
); // of broken iphlpapi!
|
||
|
||
if ( ( status == NO_ERROR ) &&
|
||
( fGetIpAddrs || g_IsDnsServer ) )
|
||
{
|
||
plocalIpArray = Dns_CreateIpArrayCopy( ptempArray );
|
||
|
||
//
|
||
// Go the subnet mask(s)
|
||
//
|
||
// DCR_QUESTION: why failure case on getting subnets
|
||
// if doesn't work then IP help gave bad info and
|
||
// we should just agree we are dead
|
||
//
|
||
// DCR_FIX: default subnetting is class B!
|
||
//
|
||
|
||
ptempArray->AddrCount = 0;
|
||
status = IpHelp_ParseIpAddressString(
|
||
ptempArray,
|
||
&pipAdapter->IpAddressList,
|
||
TRUE, // Get the subnet mask(s)
|
||
TRUE ); // Reverse the order because
|
||
// of broken iphlpapi!
|
||
if ( status == NO_ERROR )
|
||
{
|
||
psubnetIpArray = Dns_CreateIpArrayCopy( ptempArray );
|
||
}
|
||
else
|
||
{
|
||
psubnetIpArray = Dns_CreateIpArrayCopy( plocalIpArray );
|
||
if ( psubnetIpArray )
|
||
{
|
||
DWORD i;
|
||
|
||
for ( i=0;
|
||
i < psubnetIpArray->AddrCount;
|
||
i++ )
|
||
{
|
||
psubnetIpArray->AddrArray[i] = 0x0000ffff;
|
||
}
|
||
status = NO_ERROR;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Skip;
|
||
}
|
||
|
||
//
|
||
// get per-adapter information from the iphlpapi.dll.
|
||
// -- autonet
|
||
// -- DNS server list
|
||
//
|
||
|
||
status = IpHelp_GetPerAdapterInfo(
|
||
pipAdapter->Index,
|
||
& pperAdapterInfo );
|
||
|
||
if ( status == NO_ERROR )
|
||
{
|
||
if ( pperAdapterInfo->AutoconfigEnabled &&
|
||
pperAdapterInfo->AutoconfigActive )
|
||
{
|
||
adapterFlags |= DNS_FLAG_IS_AUTONET_ADAPTER;
|
||
}
|
||
}
|
||
|
||
//
|
||
// build DNS servers list for adapter
|
||
// - if policy override use it
|
||
// - otherwise use IP help list
|
||
//
|
||
|
||
if ( regInfo.pDnsServerArray )
|
||
{
|
||
pserverIpArray = regInfo.pDnsServerArray;
|
||
}
|
||
|
||
else if ( status == NO_ERROR )
|
||
{
|
||
// parse DNS servers from IP help
|
||
//
|
||
// DCR: must be able to get IPv6
|
||
|
||
pserverIpArray = ptempArray;
|
||
|
||
ptempArray->AddrCount = 0;
|
||
status = IpHelp_ParseIpAddressString(
|
||
ptempArray,
|
||
&pperAdapterInfo->DnsServerList,
|
||
FALSE, // get IP addresses
|
||
FALSE // no reverse
|
||
);
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
//
|
||
// if no DNS servers found -- write loopback if on DNS server
|
||
//
|
||
// DCR: should we bother to write -- why not just use in
|
||
// memory?
|
||
//
|
||
|
||
if ( g_IsDnsServer &&
|
||
!(adapterFlags & DNS_FLAG_IS_DHCP_CFG_ADAPTER) &&
|
||
plocalIpArray &&
|
||
psubnetIpArray )
|
||
{
|
||
Reg_WriteLoopbackDnsServerList(
|
||
pipAdapter->AdapterName,
|
||
pregSession );
|
||
|
||
ptempArray->AddrCount = 1;
|
||
ptempArray->AddrArray[0] = DNS_NET_ORDER_LOOPBACK;
|
||
}
|
||
else // no DNS servers
|
||
{
|
||
pserverIpArray = NULL;
|
||
goto Skip;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// build adapter info
|
||
//
|
||
// optionally add IP and subnet list; note this is
|
||
// direct add of data (not alloc\copy) so clear pointers
|
||
// after to skip free
|
||
//
|
||
|
||
padapter = AdapterInfo_CreateFromIpArray(
|
||
pserverIpArray,
|
||
adapterFlags,
|
||
padapterDomainName,
|
||
pipAdapter->AdapterName );
|
||
if ( padapter )
|
||
{
|
||
padapter->InterfaceIndex = pipAdapter->Index;
|
||
|
||
if ( fGetIpAddrs &&
|
||
plocalIpArray &&
|
||
psubnetIpArray )
|
||
{
|
||
padapter->pAdapterIPAddresses = plocalIpArray;
|
||
plocalIpArray = NULL;
|
||
padapter->pAdapterIPSubnetMasks = psubnetIpArray;
|
||
psubnetIpArray = NULL;
|
||
}
|
||
|
||
NetInfo_AddAdapter(
|
||
pnetInfo,
|
||
padapter );
|
||
}
|
||
|
||
Skip:
|
||
//
|
||
// cleanup adapter specific data
|
||
//
|
||
// note: no free of pserverIpArray, it IS the
|
||
// ptempArray buffer that we free at the end
|
||
//
|
||
|
||
Reg_FreeAdapterInfo(
|
||
®AdapterInfo,
|
||
FALSE // don't free blob, it is on stack
|
||
);
|
||
|
||
if ( pperAdapterInfo )
|
||
{
|
||
FREE_HEAP( pperAdapterInfo );
|
||
pperAdapterInfo = NULL;
|
||
}
|
||
if ( plocalIpArray )
|
||
{
|
||
FREE_HEAP( plocalIpArray );
|
||
plocalIpArray = NULL;
|
||
}
|
||
if ( psubnetIpArray )
|
||
{
|
||
FREE_HEAP( psubnetIpArray );
|
||
psubnetIpArray = NULL;
|
||
}
|
||
|
||
// get next adapter
|
||
// reset status, so failure on the last adapter is not
|
||
// seen as global failure
|
||
|
||
pipAdapter = pipAdapter->Next;
|
||
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// eliminate unreachable DNS servers
|
||
//
|
||
|
||
if ( g_ScreenUnreachableServers )
|
||
{
|
||
StrikeOutUnreachableDnsServers( pnetInfo );
|
||
}
|
||
|
||
//
|
||
// build search list for network info
|
||
// - skip if no active adapters found
|
||
//
|
||
// DCR: shouldn't build search list?
|
||
//
|
||
// DCR: only build if actually read search list
|
||
//
|
||
|
||
if ( pnetInfo->AdapterCount )
|
||
{
|
||
pnetInfo->pSearchList = SearchList_Build(
|
||
regInfo.pszPrimaryDomainName,
|
||
pregSession,
|
||
NULL, // no explicit key
|
||
pnetInfo,
|
||
regInfo.fUseNameDevolution,
|
||
regInfo.fUseDotLocalDomain
|
||
);
|
||
}
|
||
|
||
//
|
||
// host and domain name info
|
||
//
|
||
|
||
pnetInfo->pszDomainName = Dns_CreateStringCopy(
|
||
regInfo.pszPrimaryDomainName,
|
||
0 );
|
||
pnetInfo->pszHostName = Dns_CreateStringCopy(
|
||
regInfo.pszHostName,
|
||
0 );
|
||
|
||
// timestamp
|
||
|
||
pnetInfo->TimeStamp = Dns_GetCurrentTimeInSeconds();
|
||
|
||
|
||
Cleanup:
|
||
|
||
// free allocated reg info
|
||
|
||
Reg_FreeGlobalInfo(
|
||
pregInfo,
|
||
FALSE // don't free blob, it is on stack
|
||
);
|
||
|
||
if ( pipAdapterInfo )
|
||
{
|
||
FREE_HEAP( pipAdapterInfo );
|
||
}
|
||
if ( ptempArray )
|
||
{
|
||
FREE_HEAP( ptempArray );
|
||
}
|
||
if ( pnetInfo &&
|
||
pnetInfo->AdapterCount == 0 )
|
||
{
|
||
status = DNS_ERROR_NO_DNS_SERVERS;
|
||
}
|
||
|
||
// close registry session
|
||
|
||
Reg_CloseSession( pregSession );
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
NetInfo_Free( pnetInfo );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave: NetInfo_Build()\n"
|
||
"\tstatus = %d\n",
|
||
status ));
|
||
|
||
SetLastError( status );
|
||
return( NULL );
|
||
}
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave: NetInfo_Build()\n"
|
||
"\treturning fresh built network info (%p)\n",
|
||
pnetInfo ));
|
||
|
||
return( pnetInfo );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Network info caching\state routines
|
||
//
|
||
|
||
VOID
|
||
InitNetworkInfo(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize network info.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// currently using general CS as netinfo cache lock
|
||
// so no real init here
|
||
//
|
||
|
||
// InitializeCriticalSection( &csNetworkInfo );
|
||
g_pNetInfo = NULL;
|
||
}
|
||
|
||
|
||
VOID
|
||
CleanupNetworkInfo(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize network info.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNS_NETINFO pold;
|
||
|
||
LOCK_NETINFO();
|
||
|
||
NetInfo_Free( g_pNetInfo );
|
||
g_pNetInfo = NULL;
|
||
|
||
UNLOCK_NETINFO();
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Read config from resolver
|
||
//
|
||
|
||
PDNS_NETINFO
|
||
UpdateDnsConfig(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Update DNS configuration.
|
||
|
||
This includes entire config
|
||
- flat registry DWORD\BOOL globals
|
||
- netinfo list
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
Ptr to network info blob.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status = ERROR_SUCCESS;
|
||
PDNS_NETINFO pnetworkInfo = NULL;
|
||
PDNS_GLOBALS_BLOB pglobalsBlob = NULL;
|
||
|
||
DNSDBG( TRACE, ( "UpdateDnsConfig()\n" ));
|
||
|
||
#if DNSBUILDOLD
|
||
if ( !g_IsWin2000 )
|
||
{
|
||
return NULL;
|
||
}
|
||
#endif
|
||
|
||
|
||
// DCR_CLEANUP: RPC TryExcept should be in RPC client library
|
||
|
||
RpcTryExcept
|
||
{
|
||
R_ResolverGetConfig(
|
||
NULL, // default handle
|
||
g_ConfigCookie,
|
||
& pnetworkInfo,
|
||
& pglobalsBlob
|
||
);
|
||
}
|
||
RpcExcept( DNS_RPC_EXCEPTION_FILTER )
|
||
{
|
||
status = RpcExceptionCode();
|
||
}
|
||
RpcEndExcept
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
DNSDBG( RPC, (
|
||
"R_ResolverGetConfig() RPC failed status = %d\n",
|
||
status ));
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// DCR: save other config info here
|
||
// - flat memcpy of DWORD globals
|
||
// - save off cookie (perhaps include as one of them
|
||
// - save global copy of pnetworkInfo?
|
||
// (the idea being that we just copy it if
|
||
// RPC cookie is valid)
|
||
//
|
||
// - maybe return flags?
|
||
// memcpy is cheap but if more expensive config
|
||
// then could alert what needs update?
|
||
//
|
||
|
||
//
|
||
// DCR: once move, single "update global network info"
|
||
// then call it here to save global copy
|
||
// but global copy doesn't do much until RPC fails
|
||
// unless using cookie
|
||
//
|
||
|
||
|
||
// QUESTION: not sure about forcing global build here
|
||
// q: is this to be "read config" all
|
||
// or just "update config" and then individual
|
||
// routines for various pieces of config can
|
||
// determine what to do?
|
||
//
|
||
// note, doing eveything is fine if going to always
|
||
// read entire registry on cache failure; if so
|
||
// reasonable to push here
|
||
//
|
||
// if cache-on required for "real time" config, then
|
||
// should protect registry DWORD read with reasonable time
|
||
// (say read every five\ten\fifteen minutes?)
|
||
//
|
||
// perhaps NO read here, but have DWORD reg read update
|
||
// routine that called before registry reread when
|
||
// building adapter list in registry; then skip this
|
||
// step in cache
|
||
//
|
||
|
||
//
|
||
// copy in config
|
||
//
|
||
|
||
if ( pglobalsBlob )
|
||
{
|
||
RtlCopyMemory(
|
||
& DnsGlobals,
|
||
pglobalsBlob,
|
||
sizeof(DnsGlobals) );
|
||
|
||
MIDL_user_free( pglobalsBlob );
|
||
}
|
||
|
||
IF_DNSDBG( RPC )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"Network Info returned from cache:",
|
||
pnetworkInfo );
|
||
}
|
||
|
||
return pnetworkInfo;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Public netinfo routine
|
||
//
|
||
|
||
PDNS_NETINFO
|
||
NetInfo_Get(
|
||
IN BOOL fForce,
|
||
IN BOOL fGetIpAddresses
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Read DNS network info from registry.
|
||
|
||
This is in process, limited caching version.
|
||
Note, this is macro'd as GetNetworkInfo() with parameters
|
||
NetInfo_Get( FALSE, TRUE ) throughout dnsapi code.
|
||
|
||
Arguments:
|
||
|
||
fForce -- force reread from registry
|
||
|
||
fGetIpAddresses -- keep the local IP addresses for each adapter
|
||
and store within the structure.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO pnetInfo;
|
||
PDNS_NETINFO poldNetInfo = NULL;
|
||
BOOL flocked = FALSE;
|
||
BOOL fcacheable = TRUE;
|
||
|
||
DNSDBG( NETINFO, ( "NetInfo_Get()\n" ));
|
||
|
||
|
||
//
|
||
// hold lock while accessing cached network info
|
||
//
|
||
// try
|
||
// - very recent local cached copy
|
||
// - RPC copy from resolver
|
||
// - build new
|
||
//
|
||
|
||
if ( ! fForce &&
|
||
! g_DnsTestMode )
|
||
{
|
||
LOCK_NETINFO();
|
||
flocked = TRUE;
|
||
|
||
// check if valid copy cached in process
|
||
|
||
if ( g_pNetInfo &&
|
||
(g_pNetInfo->TimeStamp + NETINFO_CACHE_TIMEOUT)
|
||
> Dns_GetCurrentTimeInSeconds() )
|
||
{
|
||
pnetInfo = NetInfo_Copy( g_pNetInfo );
|
||
if ( pnetInfo )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"Netinfo found in process cache.\n" ));
|
||
goto Unlock;
|
||
}
|
||
}
|
||
|
||
// check RPC to resolver
|
||
//
|
||
// DCR: this could present "cookie" of existing netinfo
|
||
// and only get new if "cookie" is old, though the
|
||
// cost of that versus local copy seems small since
|
||
// still must do RPC and allocations -- only the copy
|
||
// for RPC on the resolver side is saved
|
||
|
||
pnetInfo = UpdateDnsConfig();
|
||
if ( pnetInfo )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"Netinfo read from resolver.\n" ));
|
||
goto CacheCopy;
|
||
}
|
||
}
|
||
|
||
//
|
||
// build fresh network info
|
||
// - if successful clear "dirty" flag
|
||
//
|
||
// Note: we call down unlocked. Ideally we'd have only one thread
|
||
// in the process building at a given time, and let other threads
|
||
// wait for completion. However during call down, iphlpapi RPCs
|
||
// to MPR (router service) which can result in deadlock through
|
||
// a PPP call back to our DnsSetDwordConfig() => NetInfo_MarkDirty.
|
||
//
|
||
// Here's the deadlock scenario:
|
||
// 1. RtrMgr calls GetHostByName() which ends up in a
|
||
// iphlpapi!GetBestInterface call which in turn calls
|
||
// Mprapi!IsRouterRunning (which is an RPC to mprdim).
|
||
// 2. Mprdim is blocked on a CS which is held by a thread waiting
|
||
// for a demand-dial disconnect to complete - this is completely
|
||
// independent of 1.
|
||
// 3. Demand-dial disconnect is waiting for ppp to finish graceful
|
||
// termination.
|
||
// 4. PPP is waiting for dnsto return from DnsSetConfigDword, hence
|
||
// the deadlock.
|
||
//
|
||
// This gave us a deadlock because NetInfo_MarkDirty() also waits
|
||
// on this lock. MarkDirty could skip the lock -- one method would be
|
||
// to have this function clear the dirty flag, then call down again
|
||
// IF it got done and the flag was again dirty. But that method could
|
||
// result if something is bogus down below. And even if MarkDirty is
|
||
// fixed cleanly we still have the possibility that some service that
|
||
// IpHlpApi RPCs to, will issue name resolution and come back to the
|
||
// lock on a different thread. (Because our many services in process
|
||
// model is busted.)
|
||
//
|
||
// So best solution is not to do anything this big while holding a lock.
|
||
// (We could do hacking stuff here like have an event and wait for a
|
||
// second or so before figuring we were part of a deadlock and proceeding.)
|
||
//
|
||
// Finally note that the perf hit is negligible because usually the netinfo
|
||
// is grabbed from the resolver.
|
||
//
|
||
|
||
if ( flocked )
|
||
{
|
||
UNLOCK_NETINFO();
|
||
flocked = FALSE;
|
||
}
|
||
pnetInfo = NetInfo_Build( fGetIpAddresses );
|
||
if ( !pnetInfo )
|
||
{
|
||
goto Unlock;
|
||
}
|
||
fcacheable = fGetIpAddresses;
|
||
|
||
|
||
CacheCopy:
|
||
|
||
//
|
||
// update cached copy
|
||
// - but not if built without local IPs;
|
||
// resolver copy always contains local IPs
|
||
//
|
||
|
||
if ( fcacheable )
|
||
{
|
||
if ( !flocked )
|
||
{
|
||
LOCK_NETINFO();
|
||
flocked = TRUE;
|
||
}
|
||
poldNetInfo = g_pNetInfo;
|
||
g_pNetInfo = NetInfo_Copy( pnetInfo );
|
||
}
|
||
|
||
|
||
Unlock:
|
||
|
||
if ( flocked )
|
||
{
|
||
UNLOCK_NETINFO();
|
||
}
|
||
|
||
NetInfo_Free( poldNetInfo );
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave: NetInfo_Get( %p )\n",
|
||
pnetInfo ));
|
||
|
||
return( pnetInfo );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NetInfo_MarkDirty(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Mark netinfo dirty so force reread.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO pold;
|
||
|
||
DNSDBG( NETINFO, ( "NetInfo_MarkDirty()\n" ));
|
||
|
||
//
|
||
// dump global network info to force reread
|
||
//
|
||
// since the resolve is always notified by DnsSetDwordConfig()
|
||
// BEFORE entering this function, the resolve should always be
|
||
// providing before we are in this function; all we need to do
|
||
// is insure that cached copy is dumped
|
||
//
|
||
|
||
LOCK_NETINFO();
|
||
|
||
pold = g_pNetInfo;
|
||
g_pNetInfo = NULL;
|
||
|
||
UNLOCK_NETINFO();
|
||
|
||
NetInfo_Free( pold );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// DNS server list
|
||
//
|
||
|
||
PIP4_ARRAY
|
||
GetDnsServerList(
|
||
IN BOOL fForce
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get DNS server list as IP array.
|
||
|
||
Arguments:
|
||
|
||
fForce -- force reread from registry
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO pnetInfo = NULL;
|
||
PIP_ARRAY pserverIpArray = NULL;
|
||
|
||
DNSDBG( TRACE, ( "GetDnsServerList()" ));
|
||
|
||
//
|
||
// get network info to make list from
|
||
// - don't need IP address lists
|
||
//
|
||
|
||
pnetInfo = NetInfo_Get(
|
||
fForce, // force registry read
|
||
FALSE // no IP address lists
|
||
);
|
||
if ( !pnetInfo )
|
||
{
|
||
SetLastError( DNS_ERROR_NO_DNS_SERVERS );
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// convert network info to IP_ARRAY
|
||
//
|
||
|
||
pserverIpArray = NetInfo_ConvertToIpArray( pnetInfo );
|
||
|
||
NetInfo_Free( pnetInfo );
|
||
|
||
if ( !pserverIpArray )
|
||
{
|
||
SetLastError( DNS_ERROR_NO_MEMORY );
|
||
return( NULL );
|
||
}
|
||
|
||
// if no servers read, return
|
||
|
||
if ( pserverIpArray->AddrCount == 0 )
|
||
{
|
||
FREE_HEAP( pserverIpArray );
|
||
DNS_PRINT((
|
||
"Dns_GetDnsServerList() failed: no DNS servers found\n"
|
||
"\tstatus = %d\n" ));
|
||
SetLastError( DNS_ERROR_NO_DNS_SERVERS );
|
||
return( NULL );
|
||
}
|
||
|
||
IF_DNSDBG( NETINFO )
|
||
{
|
||
DnsDbg_IpArray(
|
||
"DNS server list",
|
||
"server",
|
||
pserverIpArray );
|
||
}
|
||
|
||
return( pserverIpArray );
|
||
}
|
||
|
||
//
|
||
// End netinfo.c
|
||
//
|