4563 lines
104 KiB
C
4563 lines
104 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
|
||
|
||
|
||
|
||
// 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 (15) // 15 seconds
|
||
|
||
BOOL g_NetInfoCacheLockInitialized = FALSE;
|
||
CRITICAL_SECTION g_NetInfoCacheLock;
|
||
|
||
#define LOCK_NETINFO_CACHE() EnterCriticalSection( &g_NetInfoCacheLock );
|
||
#define UNLOCK_NETINFO_CACHE() LeaveCriticalSection( &g_NetInfoCacheLock );
|
||
|
||
//
|
||
// Netinfo build requires drop into other services
|
||
// which could
|
||
// a) be waiting
|
||
// b) have dependencies back on DNS
|
||
// so we protect with timed lock -- failing if not complete in a few seconds.
|
||
//
|
||
|
||
BOOL g_NetInfoBuildLockInitialized = FALSE;
|
||
TIMED_LOCK g_NetInfoBuildLock;
|
||
|
||
#define LOCK_NETINFO_BUILD() TimedLock_Enter( &g_NetInfoBuildLock, 5000 );
|
||
#define UNLOCK_NETINFO_BUILD() TimedLock_Leave( &g_NetInfoBuildLock );
|
||
|
||
|
||
//
|
||
// DNS_ADDR screening
|
||
//
|
||
// Use a user-defined field in DNS_ADDR as screening mask, in screening function.
|
||
// Mask is set in screening address.
|
||
|
||
#define DnsAddrFlagScreeningMask DnsAddrUser1Dword1
|
||
|
||
|
||
|
||
|
||
|
||
VOID
|
||
AdapterInfo_Free(
|
||
IN OUT PDNS_ADAPTER pAdapter,
|
||
IN BOOL fFreeAdapterStruct
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free DNS_ADAPTER structure.
|
||
|
||
Arguments:
|
||
|
||
pAdapter -- pointer to adapter blob to free
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, ( "AdapterInfo_Free( %p, %d )\n", pAdapter, fFreeAdapterStruct ));
|
||
|
||
if ( !pAdapter )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if ( pAdapter->pszAdapterGuidName )
|
||
{
|
||
FREE_HEAP( pAdapter->pszAdapterGuidName );
|
||
}
|
||
if ( pAdapter->pszAdapterDomain )
|
||
{
|
||
FREE_HEAP( pAdapter->pszAdapterDomain );
|
||
}
|
||
if ( pAdapter->pLocalAddrs )
|
||
{
|
||
FREE_HEAP( pAdapter->pLocalAddrs );
|
||
}
|
||
if ( pAdapter->pDnsAddrs )
|
||
{
|
||
FREE_HEAP( pAdapter->pDnsAddrs );
|
||
}
|
||
|
||
if ( fFreeAdapterStruct )
|
||
{
|
||
FREE_HEAP( pAdapter );
|
||
}
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
AdapterInfo_Init(
|
||
OUT PDNS_ADAPTER pAdapter,
|
||
IN BOOL fZeroInit,
|
||
IN DWORD InfoFlags,
|
||
IN PWSTR pszGuidName,
|
||
IN PWSTR pszDomain,
|
||
IN PDNS_ADDR_ARRAY pLocalAddrs,
|
||
IN PDNS_ADDR_ARRAY pDnsAddrs
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Init adapter info blob.
|
||
|
||
This sets the blob DIRECTLY with these pointers,
|
||
no reallocation.
|
||
|
||
Arguments:
|
||
|
||
pAdapter -- adapter blob to fill in
|
||
|
||
fZeroInit -- clear to zero
|
||
|
||
InfoFlags -- flags
|
||
|
||
pszGuidName -- GUID name
|
||
|
||
pszAdapterDomain -- adapter domain name
|
||
|
||
pLocalAddrs -- local addrs
|
||
|
||
pDnsAddrs -- DNS server addrs
|
||
|
||
Return Value:
|
||
|
||
Ptr to adapter info, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, ( "AdapterInfo_Init()\n" ));
|
||
|
||
//
|
||
// setup adapter info blob
|
||
//
|
||
|
||
if ( fZeroInit )
|
||
{
|
||
RtlZeroMemory(
|
||
pAdapter,
|
||
sizeof( *pAdapter ) );
|
||
}
|
||
|
||
// names
|
||
|
||
pAdapter->pszAdapterGuidName = pszGuidName;
|
||
pAdapter->pszAdapterDomain = pszDomain;
|
||
pAdapter->pLocalAddrs = pLocalAddrs;
|
||
pAdapter->pDnsAddrs = pDnsAddrs;
|
||
|
||
// if no DNS servers -- set ignore flag
|
||
|
||
if ( fZeroInit && !pDnsAddrs )
|
||
{
|
||
InfoFlags |= AINFO_FLAG_IGNORE_ADAPTER;
|
||
}
|
||
|
||
pAdapter->InfoFlags = InfoFlags;
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
AdapterInfo_Create(
|
||
OUT PDNS_ADAPTER pAdapter,
|
||
IN BOOL fZeroInit,
|
||
IN DWORD InfoFlags,
|
||
IN PWSTR pszGuidName,
|
||
IN PWSTR pszDomain,
|
||
IN PDNS_ADDR_ARRAY pLocalAddrs,
|
||
IN PDNS_ADDR_ARRAY pDnsAddrs
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create adapter info blob.
|
||
|
||
This initializes blob with copies of names and addr arrays
|
||
provided.
|
||
|
||
Arguments:
|
||
|
||
pAdapter -- adapter blob to fill in
|
||
|
||
fZeroInit -- clear to zero
|
||
|
||
InfoFlags -- flags
|
||
|
||
pszGuidName -- GUID name
|
||
|
||
pszAdapterDomain -- adapter domain name
|
||
|
||
pLocalAddrs -- local addrs
|
||
|
||
pDnsAddrs -- DNS server addrs
|
||
|
||
Return Value:
|
||
|
||
Ptr to adapter info, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADDR_ARRAY paddrs;
|
||
PWSTR pname;
|
||
|
||
DNSDBG( TRACE, ( "AdapterInfo_Create()\n" ));
|
||
|
||
//
|
||
// setup adapter info blob
|
||
//
|
||
|
||
if ( fZeroInit )
|
||
{
|
||
RtlZeroMemory(
|
||
pAdapter,
|
||
sizeof( *pAdapter ) );
|
||
}
|
||
|
||
// names
|
||
|
||
if ( pszGuidName )
|
||
{
|
||
pname = Dns_CreateStringCopy_W( pszGuidName );
|
||
if ( !pname )
|
||
{
|
||
goto Failed;
|
||
}
|
||
pAdapter->pszAdapterGuidName = pname;
|
||
}
|
||
if ( pszDomain )
|
||
{
|
||
pname = Dns_CreateStringCopy_W( pszDomain );
|
||
if ( !pname )
|
||
{
|
||
goto Failed;
|
||
}
|
||
pAdapter->pszAdapterDomain = pname;
|
||
}
|
||
|
||
// addresses
|
||
|
||
if ( pLocalAddrs )
|
||
{
|
||
paddrs = DnsAddrArray_CreateCopy( pLocalAddrs );
|
||
if ( !paddrs )
|
||
{
|
||
goto Failed;
|
||
}
|
||
pAdapter->pLocalAddrs = paddrs;
|
||
}
|
||
if ( pDnsAddrs )
|
||
{
|
||
paddrs = DnsAddrArray_CreateCopy( pDnsAddrs );
|
||
if ( !paddrs )
|
||
{
|
||
goto Failed;
|
||
}
|
||
pAdapter->pDnsAddrs = paddrs;
|
||
}
|
||
|
||
// if no DNS servers -- set ignore flag
|
||
|
||
if ( fZeroInit && !paddrs )
|
||
{
|
||
InfoFlags |= AINFO_FLAG_IGNORE_ADAPTER;
|
||
}
|
||
|
||
pAdapter->InfoFlags = InfoFlags;
|
||
|
||
return NO_ERROR;
|
||
|
||
Failed:
|
||
|
||
AdapterInfo_Free(
|
||
pAdapter,
|
||
FALSE // no structure free
|
||
);
|
||
|
||
return DNS_ERROR_NO_MEMORY;
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
AdapterInfo_Copy(
|
||
OUT PDNS_ADAPTER pCopy,
|
||
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.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status;
|
||
|
||
DNSDBG( TRACE, ( "AdapterInfo_Copy( %p )\n", pAdapter ));
|
||
|
||
if ( !pAdapter || !pCopy )
|
||
{
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// copy all fields
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
pCopy,
|
||
pAdapter,
|
||
sizeof( *pAdapter ) );
|
||
|
||
pCopy->pszAdapterGuidName = NULL;
|
||
pCopy->pszAdapterDomain = NULL;
|
||
pCopy->pLocalAddrs = NULL;
|
||
pCopy->pDnsAddrs = NULL;
|
||
|
||
//
|
||
// do create copy
|
||
//
|
||
|
||
return AdapterInfo_Create(
|
||
pCopy,
|
||
FALSE, // no zero init
|
||
pAdapter->InfoFlags,
|
||
pAdapter->pszAdapterGuidName,
|
||
pAdapter->pszAdapterDomain,
|
||
pAdapter->pLocalAddrs,
|
||
pAdapter->pDnsAddrs );
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
AdapterInfo_CreateFromIp4Array(
|
||
OUT PDNS_ADAPTER pAdapter,
|
||
IN PIP4_ARRAY pServerArray,
|
||
IN DWORD Flags,
|
||
IN PWSTR pszDomainName,
|
||
IN PWSTR pszGuidName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of IP address array as a DNS Server list.
|
||
|
||
Arguments:
|
||
|
||
pIpArray -- IP address array to convert
|
||
|
||
Flags -- 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:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
ErrorCode on error.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status;
|
||
PDNS_ADDR_ARRAY pdnsArray;
|
||
DWORD i;
|
||
DWORD count;
|
||
|
||
DNSDBG( TRACE, ( "AdapterInfo_CreateFromIp4Array()\n" ));
|
||
|
||
//
|
||
// get count of DNS servers
|
||
//
|
||
|
||
if ( !pServerArray )
|
||
{
|
||
count = 0;
|
||
}
|
||
else
|
||
{
|
||
count = pServerArray->AddrCount;
|
||
}
|
||
|
||
//
|
||
// copy DNS server IPs
|
||
//
|
||
|
||
pdnsArray = DnsAddrArray_CreateFromIp4Array( pServerArray );
|
||
if ( !pdnsArray )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// build adapter info
|
||
//
|
||
|
||
status = AdapterInfo_Create(
|
||
pAdapter,
|
||
TRUE, // zero init
|
||
Flags,
|
||
pszDomainName,
|
||
pszGuidName,
|
||
NULL,
|
||
pdnsArray );
|
||
|
||
Done:
|
||
|
||
DnsAddrArray_Free( pdnsArray );
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// Search list routines
|
||
//
|
||
|
||
PSEARCH_LIST
|
||
SearchList_Alloc(
|
||
IN DWORD MaxNameCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create uninitialized search list.
|
||
|
||
Arguments:
|
||
|
||
NameCount -- count of search names list will hold
|
||
|
||
Return Value:
|
||
|
||
Ptr to uninitialized DNS search list, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PSEARCH_LIST psearchList = NULL;
|
||
DWORD length;
|
||
|
||
DNSDBG( TRACE, ( "SearchList_Alloc()\n" ));
|
||
|
||
//
|
||
// note: specifically allowing alloc even if no name count
|
||
// or domain name as could have no PDN and still need
|
||
// search list referenced in query
|
||
//
|
||
#if 0
|
||
if ( MaxNameCount == 0 )
|
||
{
|
||
return NULL;
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// 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;
|
||
|
||
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 ));
|
||
|
||
//
|
||
// free all search names, then list itself
|
||
//
|
||
|
||
if ( pSearchList )
|
||
{
|
||
for ( i=0; i < pSearchList->NameCount; i++ )
|
||
{
|
||
PWSTR 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 );
|
||
if ( ! pcopy )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
for ( i=0; i < pSearchList->NameCount; i++ )
|
||
{
|
||
PWSTR pname = pSearchList->SearchNameArray[i].pszName;
|
||
|
||
if ( pname )
|
||
{
|
||
pname = Dns_CreateStringCopy_W( pname );
|
||
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 PWSTR 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_W(
|
||
pSearchList->SearchNameArray[ count ].pszName,
|
||
pszName ) )
|
||
{
|
||
return( TRUE );
|
||
}
|
||
}
|
||
return( FALSE );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
SearchList_AddName(
|
||
IN OUT PSEARCH_LIST pSearchList,
|
||
IN PWSTR 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;
|
||
PWSTR 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_W( pszName );
|
||
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 PWSTR 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 PWCHAR pch = pszList;
|
||
WCHAR ch;
|
||
PWCHAR pnameStart;
|
||
PWSTR pname;
|
||
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 < 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 != L' ' && ch != L'\t' && ch != L'\0' && ch != L',' )
|
||
{
|
||
ch = *++pch;
|
||
}
|
||
*pch = L'\0';
|
||
|
||
//
|
||
// end of buffer?
|
||
//
|
||
|
||
if ( pch == pnameStart )
|
||
{
|
||
break;
|
||
}
|
||
|
||
//
|
||
// whack any trailing dot on name
|
||
//
|
||
|
||
pch--;
|
||
if ( *pch == L'.' )
|
||
{
|
||
*pch = L'\0';
|
||
}
|
||
pch++;
|
||
|
||
//
|
||
// make copy of the name
|
||
//
|
||
|
||
pname = Dns_CreateStringCopy_W( pnameStart );
|
||
if ( pname )
|
||
{
|
||
pSearchList->SearchNameArray[ countNames ].pszName = pname;
|
||
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 PWSTR pszPrimaryDomainName,
|
||
IN PREG_SESSION pRegSession,
|
||
IN HKEY hKey,
|
||
IN OUT PDNS_NETINFO pNetInfo,
|
||
IN BOOL fUseDomainNameDevolution
|
||
)
|
||
/*++
|
||
|
||
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;
|
||
PWSTR pregList = NULL;
|
||
DWORD status;
|
||
|
||
|
||
DNSDBG( TRACE, ( "Search_ListBuild()\n" ));
|
||
|
||
ASSERT( pRegSession || hKey );
|
||
|
||
//
|
||
// create search list using PDN
|
||
//
|
||
|
||
ptempList = SearchList_Alloc( MAX_SEARCH_LIST_ENTRIES );
|
||
if ( !ptempList )
|
||
{
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// read search list from registry
|
||
//
|
||
|
||
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 );
|
||
}
|
||
else if ( status == DNS_ERROR_NO_MEMORY )
|
||
{
|
||
FREE_HEAP( ptempList );
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// if no registry search list -- build one
|
||
//
|
||
// DCR: eliminate autobuilt search list
|
||
//
|
||
|
||
if ( ! ptempList->NameCount )
|
||
{
|
||
//
|
||
// use PDN in first search list slot
|
||
//
|
||
|
||
if ( pszPrimaryDomainName )
|
||
{
|
||
SearchList_AddName(
|
||
ptempList,
|
||
pszPrimaryDomainName,
|
||
0 );
|
||
}
|
||
|
||
//
|
||
// add devolved PDN if have NameDevolution
|
||
//
|
||
// note, we devolve only down to second level
|
||
// domain name "microsoft.com" NOT "com";
|
||
// to avoid being fooled by name like "com."
|
||
// also check that last dot is not terminal
|
||
//
|
||
|
||
if ( pszPrimaryDomainName && fUseDomainNameDevolution )
|
||
{
|
||
PWSTR pname = pszPrimaryDomainName;
|
||
|
||
while ( pname )
|
||
{
|
||
PWSTR pnext = wcschr( pname, '.' );
|
||
|
||
if ( !pnext )
|
||
{
|
||
break;
|
||
}
|
||
pnext++;
|
||
if ( !*pnext )
|
||
{
|
||
//DNS_ASSERT( FALSE );
|
||
break;
|
||
}
|
||
|
||
// add name, but not on first pass
|
||
// - already have PDN in first slot
|
||
|
||
if ( pname != pszPrimaryDomainName )
|
||
{
|
||
SearchList_AddName(
|
||
ptempList,
|
||
pname,
|
||
DNS_QUERY_USE_QUICK_TIMEOUTS );
|
||
}
|
||
pname = pnext;
|
||
}
|
||
}
|
||
|
||
// indicate this is dummy search list
|
||
|
||
if ( pNetInfo )
|
||
{
|
||
pNetInfo->InfoFlags |= NINFO_FLAG_DUMMY_SEARCH_LIST;
|
||
}
|
||
}
|
||
|
||
return ptempList;
|
||
}
|
||
|
||
|
||
|
||
PWSTR
|
||
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;
|
||
PWSTR 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(DNS_ADAPTER)
|
||
+ (sizeof(DNS_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(
|
||
NetInfo_GetAdapterByIndex( pNetInfo, i ),
|
||
FALSE // no structure free
|
||
);
|
||
}
|
||
|
||
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;
|
||
PDNS_ADAPTER padapter;
|
||
DWORD adapterCount;
|
||
DNS_STATUS status;
|
||
DWORD iter;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_Copy( %p )\n", pNetInfo ));
|
||
|
||
if ( ! pNetInfo )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
IF_DNSDBG( OFF )
|
||
{
|
||
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;
|
||
pcopy->AdapterCount = 0;
|
||
|
||
//
|
||
// copy subcomponents
|
||
// - domain name
|
||
// - search list
|
||
//
|
||
|
||
pcopy->pszDomainName = Dns_CreateStringCopy_W( pNetInfo->pszDomainName );
|
||
pcopy->pszHostName = Dns_CreateStringCopy_W( pNetInfo->pszHostName );
|
||
|
||
pcopy->pSearchList = SearchList_Copy( pNetInfo->pSearchList );
|
||
|
||
if ( (!pcopy->pszDomainName && pNetInfo->pszDomainName) ||
|
||
(!pcopy->pszHostName && pNetInfo->pszHostName) ||
|
||
(!pcopy->pSearchList && pNetInfo->pSearchList) )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Failed;
|
||
}
|
||
|
||
//
|
||
// copy adapter info
|
||
//
|
||
|
||
adapterCount = 0;
|
||
|
||
for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
|
||
{
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
|
||
|
||
status = AdapterInfo_Copy(
|
||
&pcopy->AdapterArray[ adapterCount ],
|
||
padapter
|
||
);
|
||
if ( status == NO_ERROR )
|
||
{
|
||
pcopy->AdapterCount = ++adapterCount;
|
||
continue;
|
||
}
|
||
goto Failed;
|
||
}
|
||
|
||
IF_DNSDBG( OFF )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"Netinfo copy: ",
|
||
pcopy );
|
||
}
|
||
return pcopy;
|
||
|
||
|
||
Failed:
|
||
|
||
NetInfo_Free( pcopy );
|
||
SetLastError( status );
|
||
return NULL;
|
||
}
|
||
|
||
|
||
|
||
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
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADAPTER padapter;
|
||
DWORD iter;
|
||
|
||
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 ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
|
||
{
|
||
DWORD j;
|
||
PDNS_ADDR_ARRAY pserverArray;
|
||
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
|
||
|
||
pserverArray = padapter->pDnsAddrs;
|
||
if ( !pserverArray )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
padapter->Status = 0;
|
||
padapter->RunFlags &= ClearLevel;
|
||
|
||
// clear server status fields
|
||
|
||
for ( j=0; j<pserverArray->AddrCount; j++ )
|
||
{
|
||
pserverArray->AddrArray[j].Flags = SRVFLAG_NEW;
|
||
pserverArray->AddrArray[j].Status = SRVSTATUS_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
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADAPTER padapter;
|
||
DWORD iter;
|
||
|
||
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
|
||
//
|
||
// FIX6: local DNS check needs IP6 fixups
|
||
// DCR: encapsulate as "NetInfo_IsLocalAddress
|
||
|
||
for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
|
||
{
|
||
DWORD j;
|
||
PDNS_ADDR_ARRAY pserverArray;
|
||
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
|
||
|
||
pserverArray = padapter->pDnsAddrs;
|
||
if ( !pserverArray )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
for ( j=0; j < pserverArray->AddrCount; j++ )
|
||
{
|
||
PDNS_ADDR pserver = &pserverArray->AddrArray[j];
|
||
|
||
// loopback goes first
|
||
// - we plumb it in for specific AD scenarios
|
||
// - the cost of failure is low (should just generate
|
||
// ICMP -- CONNRESET -- if server not running)
|
||
|
||
if ( DnsAddr_IsLoopback(pserver, 0) )
|
||
{
|
||
pserver->Priority = SRVPRI_LOOPBACK;
|
||
continue;
|
||
}
|
||
|
||
if ( !fLocalDnsOnly )
|
||
{
|
||
if ( DnsAddr_IsIp6DefaultDns( pserver ) )
|
||
{
|
||
pserver->Priority = SRVPRI_IP6_DEFAULT;
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
pserver->Priority = SRVPRI_DEFAULT;
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// pull this into local test
|
||
|
||
if ( LocalIp_IsAddrLocal(
|
||
pserver,
|
||
NULL, // no local array
|
||
pNetInfo // use netinfo to screen local addrs
|
||
) )
|
||
{
|
||
pserver->Priority = SRVPRI_DEFAULT;
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADAPTER
|
||
NetInfo_GetNextAdapter(
|
||
IN OUT PDNS_NETINFO pNetInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get next adapter.
|
||
|
||
Note, this must be preceeded by a call to macro
|
||
NetInfo_StartAdapterLoop()
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- netinfo to get adapter from
|
||
note, internal index is incremented
|
||
|
||
Return Value:
|
||
|
||
Ptr to next DNS_ADAPTER
|
||
NULL when out of adapters.
|
||
|
||
--*/
|
||
{
|
||
DWORD index;
|
||
PDNS_ADAPTER padapter = NULL;
|
||
|
||
//
|
||
// get next adapter if still in range
|
||
//
|
||
|
||
index = pNetInfo->AdapterIndex;
|
||
|
||
if ( index < pNetInfo->AdapterCount )
|
||
{
|
||
padapter = &pNetInfo->AdapterArray[ index++ ];
|
||
|
||
pNetInfo->AdapterIndex = index;
|
||
}
|
||
|
||
return padapter;
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADAPTER
|
||
NetInfo_GetAdapterByName(
|
||
IN PDNS_NETINFO pNetInfo,
|
||
IN PWSTR pwsAdapterName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find adapter in netinfo by name.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- DNS net adapter list to convert
|
||
|
||
pAdapterName -- adapter name
|
||
|
||
Return Value:
|
||
|
||
Ptr to adapter, if adapter name found.
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADAPTER padapterFound = NULL;
|
||
PDNS_ADAPTER padapter;
|
||
DWORD iter;
|
||
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_GetAdapterByName( %p )\n", pNetInfo ));
|
||
|
||
if ( !pNetInfo || !pwsAdapterName )
|
||
{
|
||
SetLastError( ERROR_INVALID_PARAMETER );
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// find matching adapter
|
||
//
|
||
|
||
for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
|
||
{
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
|
||
|
||
if ( wcscmp( padapter->pszAdapterGuidName, pwsAdapterName ) == 0 )
|
||
{
|
||
padapterFound = padapter;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return( padapterFound );
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADDR_ARRAY
|
||
NetInfo_ConvertToAddrArray(
|
||
IN PDNS_NETINFO pNetInfo,
|
||
IN PWSTR pwsAdapterName,
|
||
IN DWORD Family OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create IP array of DNS servers from network info.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- DNS net adapter list to convert
|
||
|
||
pwsAdapterName -- specific adapter
|
||
|
||
Family -- required specific address family
|
||
|
||
Return Value:
|
||
|
||
Ptr to IP array, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADDR_ARRAY parray = NULL;
|
||
DWORD countServers = 0;
|
||
PDNS_ADAPTER padapter;
|
||
PDNS_ADAPTER padapterSingle = NULL;
|
||
DNS_STATUS status = NO_ERROR;
|
||
DWORD iter;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_ConvertToAddrArray( %p )\n", pNetInfo ));
|
||
|
||
//
|
||
// get count
|
||
//
|
||
|
||
if ( ! pNetInfo )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
if ( pwsAdapterName )
|
||
{
|
||
padapterSingle = NetInfo_GetAdapterByName( pNetInfo, pwsAdapterName );
|
||
if ( !padapterSingle )
|
||
{
|
||
goto Done;
|
||
}
|
||
countServers = DnsAddrArray_GetFamilyCount(
|
||
padapterSingle->pDnsAddrs,
|
||
Family );
|
||
}
|
||
else
|
||
{
|
||
for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
|
||
{
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
|
||
|
||
countServers += DnsAddrArray_GetFamilyCount(
|
||
padapter->pDnsAddrs,
|
||
Family );
|
||
}
|
||
}
|
||
|
||
//
|
||
// allocate required array
|
||
//
|
||
|
||
parray = DnsAddrArray_Create( countServers );
|
||
if ( !parray )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Done;
|
||
}
|
||
DNS_ASSERT( parray->MaxCount == countServers );
|
||
|
||
//
|
||
// read all servers into IP array
|
||
//
|
||
|
||
for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
|
||
{
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
|
||
|
||
if ( !padapterSingle ||
|
||
padapterSingle == padapter )
|
||
{
|
||
status = DnsAddrArray_AppendArrayEx(
|
||
parray,
|
||
padapter->pDnsAddrs,
|
||
0, // append all
|
||
Family, // family screen
|
||
0, // no dup screen
|
||
NULL, // no other screening
|
||
NULL // no other screening
|
||
);
|
||
|
||
DNS_ASSERT( status == NO_ERROR );
|
||
}
|
||
}
|
||
|
||
Done:
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
SetLastError( status );
|
||
}
|
||
|
||
return( parray );
|
||
}
|
||
|
||
|
||
|
||
PDNS_NETINFO
|
||
NetInfo_CreateForUpdate(
|
||
IN PWSTR pszZone,
|
||
IN PWSTR pszServerName,
|
||
IN PDNS_ADDR_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.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADAPTER padapter;
|
||
PDNS_NETINFO pnetInfo;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_CreateForUpdate()\n" ));
|
||
|
||
//
|
||
// allocate
|
||
//
|
||
|
||
pnetInfo = NetInfo_Alloc( 1 );
|
||
if ( !pnetInfo )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// save zone name
|
||
//
|
||
|
||
if ( pszZone )
|
||
{
|
||
pnetInfo->pszDomainName = Dns_CreateStringCopy_W( pszZone );
|
||
if ( !pnetInfo->pszDomainName )
|
||
{
|
||
goto Fail;
|
||
}
|
||
}
|
||
|
||
//
|
||
// convert IP array and server name to server list
|
||
//
|
||
|
||
if ( NO_ERROR != AdapterInfo_Create(
|
||
&pnetInfo->AdapterArray[0],
|
||
TRUE, // zero init
|
||
dwFlags,
|
||
NULL, // no GUID
|
||
pszServerName, // use as domain name
|
||
NULL, // no local addrs
|
||
pServerArray
|
||
) )
|
||
{
|
||
goto Fail;
|
||
}
|
||
pnetInfo->AdapterCount = 1;
|
||
|
||
IF_DNSDBG( NETINFO2 )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"Update network info is: ",
|
||
pnetInfo );
|
||
}
|
||
return pnetInfo;
|
||
|
||
Fail:
|
||
|
||
DNSDBG( TRACE, ( "Failed NetInfo_CreateForUpdate()!\n" ));
|
||
NetInfo_Free( pnetInfo );
|
||
return NULL;
|
||
}
|
||
|
||
|
||
|
||
#if 0
|
||
PDNS_NETINFO
|
||
NetInfo_CreateForUpdateIp4(
|
||
IN PWSTR pszZone,
|
||
IN PWSTR pszServerName,
|
||
IN PIP4_ARRAY pServ4Array,
|
||
IN DWORD dwFlags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create network info suitable for update -- IP4 version.
|
||
|
||
DCR: Used only by Dns_UpdateLib() once killed, kill this.
|
||
|
||
Arguments:
|
||
|
||
pszZone -- target zone name
|
||
|
||
pszServerName -- target server name
|
||
|
||
pServ4Array -- IP$ array with target server IP
|
||
|
||
dwFlags -- flags
|
||
|
||
Return Value:
|
||
|
||
Ptr to resulting update compatible network info.
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PADDR_ARRAY parray;
|
||
PDNS_NETINFO pnetInfo;
|
||
|
||
//
|
||
// convert 4 to 6, then call real routine
|
||
//
|
||
|
||
parray = DnsAddrArray_CreateFromIp4Array( pServ4Array );
|
||
|
||
pnetInfo = NetInfo_CreateForUpdate(
|
||
pszZone,
|
||
pszServerName,
|
||
parray,
|
||
dwFlags );
|
||
|
||
DnsAddrArray_Free( parray );
|
||
|
||
return pnetInfo;
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
PWSTR
|
||
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->pszDomainName;
|
||
}
|
||
|
||
|
||
|
||
PWSTR
|
||
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->pszDomainName &&
|
||
pNetInfo->AdapterCount == 1 );
|
||
}
|
||
|
||
|
||
|
||
PDNS_NETINFO
|
||
NetInfo_CreateFromAddrArray(
|
||
IN PADDR_ARRAY pDnsServers,
|
||
IN PDNS_ADDR pServerIp,
|
||
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;
|
||
ADDR_ARRAY ipArray;
|
||
PADDR_ARRAY parray = pDnsServers;
|
||
PSEARCH_LIST psearchList;
|
||
PWSTR 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 ( pServerIp )
|
||
{
|
||
DnsAddrArray_InitSingleWithAddr(
|
||
& ipArray,
|
||
pServerIp );
|
||
|
||
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_W( pNetInfo->pszDomainName );
|
||
}
|
||
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 & NINFO_FLAG_DUMMY_SEARCH_LIST);
|
||
}
|
||
|
||
return( pnetInfo );
|
||
}
|
||
|
||
|
||
|
||
#if 0
|
||
PDNS_NETINFO
|
||
NetInfo_CreateFromIp4Array(
|
||
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.
|
||
|
||
Used only in Glenn update routines -- kill when they are deleted.
|
||
|
||
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;
|
||
PWSTR 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_CreateForUpdateIp4(
|
||
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_W( pNetInfo->pszDomainName );
|
||
}
|
||
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 & NINFO_FLAG_DUMMY_SEARCH_LIST);
|
||
}
|
||
|
||
return( pnetInfo );
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
//
|
||
// NetInfo building utilities
|
||
//
|
||
// 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 PDNS_ADDR pAddr
|
||
)
|
||
/*++
|
||
|
||
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
|
||
|
||
pAddr -- DNS server address to test for reachability
|
||
|
||
Return Value:
|
||
|
||
TRUE if DNS server is reachable.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADAPTER padapter = NULL;
|
||
PDNS_ADDR_ARRAY pserverArray;
|
||
DWORD i;
|
||
PIP4_ARRAY pipArray;
|
||
PIP4_ARRAY psubnetArray;
|
||
DWORD ipCount;
|
||
IP4_ADDRESS ip4;
|
||
|
||
DNSDBG( NETINFO, (
|
||
"Enter IsDnsReachableOnAlternateInterface( %p, %d, %08x )\n",
|
||
pNetInfo,
|
||
InterfaceIndex,
|
||
pAddr ));
|
||
|
||
//
|
||
// find DNS adapter for interface
|
||
//
|
||
|
||
for( i=0; i<pNetInfo->AdapterCount; i++ )
|
||
{
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, 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;
|
||
}
|
||
|
||
//
|
||
// success conditions:
|
||
// 1) DNS IP matches IP of DNS server for send interface
|
||
// 2) DNS IP is on subnet of IP of send interface
|
||
// 3) DNS IP4 is same default class subnet of send interface
|
||
//
|
||
// if either of these is TRUE then either
|
||
// - there is misconfiguration (not our problem)
|
||
// OR
|
||
// - there's a somewhat unlikely condition of a default network address
|
||
// being subnetted in such a way that it appears on two adapters for
|
||
// the machine but is not connected and routeable
|
||
// OR
|
||
// - these interfaces are connected and we can safely send on them
|
||
//
|
||
//
|
||
// #3 is the issue of multiple adapters in the same (corporate) name space
|
||
// example:
|
||
// adapter 1 -- default gateway
|
||
// IP 157.59.1.1
|
||
// DNS 158.10.1.1
|
||
//
|
||
// adapter 2
|
||
// IP 157.59.7.9
|
||
// DNS 159.65.7.8 -- send interface adapter 1
|
||
//
|
||
// adapter 3
|
||
// IP 159.57.12.3
|
||
// DNS 157.59.134.7 -- send interface adapter 1
|
||
//
|
||
// adapter 4
|
||
// IP 196.12.13.3
|
||
// DNS 200.59.73.2
|
||
//
|
||
// From GetBestInterface, adapter 1, (default gateway) is given as send interface
|
||
// for adapter 2 and 3's DNS servers.
|
||
//
|
||
// For adapter #2, it's DNS is NOT in adapter1's list, but it's IP shares the same
|
||
// class B network as adapter 1. It is unlikely that the subnetting is such that
|
||
// it's DNS is not reachable through adapter 1.
|
||
//
|
||
// For adapter #3, it's DNS is NOT in adapter1's list, but it's DNS is on the same
|
||
// class B network as adapter 1's interface. Again it's extremely unlikely it is
|
||
// not reachable.
|
||
//
|
||
// For adapter #4, however, it's plain that there's no connection. Neither it's IP
|
||
// nor DNS share default network with adapter 1. So send -- which will go out -- adapter
|
||
// #1 has a high likelyhood of being to a disjoint network and being unreturnable.
|
||
//
|
||
//
|
||
|
||
|
||
if ( DnsAddrArray_ContainsAddr(
|
||
padapter->pDnsAddrs,
|
||
pAddr,
|
||
DNSADDR_MATCH_ADDR ) )
|
||
{
|
||
DNSDBG( NETINFO, (
|
||
"DNS server %p also DNS server on send interface %d\n",
|
||
pAddr,
|
||
InterfaceIndex ));
|
||
return( TRUE );
|
||
}
|
||
|
||
//
|
||
// DCR: should do subnet matching on IPs
|
||
// if DNS server is for one interface with IP on same subnet as IP
|
||
// of the interface you'll send on, then it should be kosher
|
||
//
|
||
|
||
//
|
||
// test for subnet match for IP4 addrs
|
||
//
|
||
// FIX6: subnet matching fixup for new subnet info
|
||
// DCR: encapsulate subnet matching -- local subnet test
|
||
//
|
||
// FIX6: local subnet matching on IP6
|
||
//
|
||
|
||
#if SUB4NET
|
||
ip4 = DnsAddr_GetIp4( pAddr );
|
||
if ( ip4 != BAD_IP4_ADDR )
|
||
{
|
||
pipArray = padapter->pIp4Addrs;
|
||
psubnetArray = padapter->pIp4SubnetMasks;
|
||
|
||
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 & ip4) == (subnet & pipArray->AddrArray[i]) )
|
||
{
|
||
DNSDBG( NETINFO, (
|
||
"DNS server %08x on subnet of IP for send interface %d\n"
|
||
"\tip = %08x, subnet = %08x\n",
|
||
ip4,
|
||
InterfaceIndex,
|
||
pipArray->AddrArray[i],
|
||
subnet ));
|
||
|
||
return( TRUE );
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
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;
|
||
PDNS_ADDR_ARRAY pserverArray;
|
||
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++ )
|
||
{
|
||
BOOL found4;
|
||
BOOL found6;
|
||
BOOL found6NonDefault;
|
||
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, i );
|
||
|
||
// ignore this adapter because there are no DNS
|
||
// servers configured?
|
||
|
||
if ( padapter->InfoFlags & AINFO_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;
|
||
|
||
//
|
||
// FIX6: need GetBestInteface for IP6
|
||
//
|
||
|
||
found4 = FALSE;
|
||
found6 = FALSE;
|
||
found6NonDefault = FALSE;
|
||
|
||
pserverArray = padapter->pDnsAddrs;
|
||
|
||
for ( j=0; j<pserverArray->AddrCount; j++ )
|
||
{
|
||
PDNS_ADDR paddr = &pserverArray->AddrArray[j];
|
||
IP4_ADDRESS ip4;
|
||
|
||
ip4 = DnsAddr_GetIp4( paddr );
|
||
|
||
//
|
||
// IP6
|
||
//
|
||
|
||
if ( ip4 == BAD_IP4_ADDR )
|
||
{
|
||
found6 = TRUE;
|
||
|
||
if ( !DnsAddr_IsIp6DefaultDns( paddr ) )
|
||
{
|
||
found6NonDefault = TRUE;
|
||
}
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// IP4 server
|
||
//
|
||
|
||
found4 = TRUE;
|
||
serverIfIndex = 0; // prefix happiness
|
||
|
||
status = IpHelp_GetBestInterface(
|
||
ip4,
|
||
& serverIfIndex );
|
||
|
||
if ( status == ERROR_NETWORK_UNREACHABLE )
|
||
{
|
||
DNSDBG( NETINFO, (
|
||
"GetBestInterface() NETWORK_UNREACH for server %s\n",
|
||
IP_STRING(ip4) ));
|
||
continue;
|
||
}
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
DNSDBG( ANY, (
|
||
"GetBestInterface() failed! %d\n",
|
||
status ));
|
||
//DNS_ASSERT( FALSE );
|
||
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,
|
||
paddr ) )
|
||
{
|
||
validServers++;
|
||
break;
|
||
//continue;
|
||
}
|
||
}
|
||
|
||
//
|
||
// mark adapter if no reachable servers found
|
||
//
|
||
// => if no servers or IP4 tested and failed, ignore the adapter
|
||
// => if only IP6 default server, mark, we'll use but not
|
||
// continue on adapter after NAME_ERROR
|
||
// =>
|
||
//
|
||
// - any IP6 will be considered "found" (until get explicit test)
|
||
// BUT if we test IP4 on that interface, then it's status wins
|
||
//
|
||
// 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 )
|
||
{
|
||
if ( found4 || !found6 )
|
||
{
|
||
padapter->InfoFlags |= (AINFO_FLAG_IGNORE_ADAPTER |
|
||
AINFO_FLAG_SERVERS_UNREACHABLE);
|
||
DNSDBG( NETINFO, (
|
||
"No reachable servers on interface %d\n"
|
||
"\tthis adapter (%p) ignored in DNS list!\n",
|
||
adapterIfIndex,
|
||
padapter ));
|
||
}
|
||
else if ( !found6NonDefault )
|
||
{
|
||
padapter->InfoFlags |= AINFO_FLAG_SERVERS_IP6_DEFAULT;
|
||
|
||
DNSDBG( NETINFO, (
|
||
"Only IP6 default servers on interface %d\n"
|
||
"\twill not continue on this adapter after response.\n",
|
||
adapterIfIndex,
|
||
padapter ));
|
||
}
|
||
}
|
||
}
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Network info caching\state routines
|
||
//
|
||
|
||
BOOL
|
||
InitNetworkInfo(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize network info.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// standard up-n-running path -- allows cheap runtime check
|
||
//
|
||
|
||
if ( g_NetInfoCacheLockInitialized &&
|
||
g_NetInfoBuildLockInitialized )
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// if netinfo not initialzied
|
||
//
|
||
|
||
LOCK_GENERAL();
|
||
|
||
g_pNetInfo = NULL;
|
||
|
||
if ( !g_NetInfoCacheLockInitialized )
|
||
{
|
||
g_NetInfoCacheLockInitialized =
|
||
( RtlInitializeCriticalSection( &g_NetInfoCacheLock ) == NO_ERROR );
|
||
}
|
||
|
||
if ( !g_NetInfoBuildLockInitialized )
|
||
{
|
||
g_NetInfoBuildLockInitialized =
|
||
( TimedLock_Initialize( &g_NetInfoBuildLock, 5000 ) == NO_ERROR );
|
||
}
|
||
|
||
UNLOCK_GENERAL();
|
||
|
||
return ( g_NetInfoCacheLockInitialized && g_NetInfoBuildLockInitialized );
|
||
}
|
||
|
||
|
||
VOID
|
||
CleanupNetworkInfo(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize network info.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
LOCK_GENERAL();
|
||
|
||
NetInfo_MarkDirty();
|
||
|
||
if ( g_NetInfoBuildLockInitialized )
|
||
{
|
||
TimedLock_Cleanup( &g_NetInfoBuildLock );
|
||
}
|
||
if ( g_NetInfoCacheLockInitialized )
|
||
{
|
||
DeleteCriticalSection( &g_NetInfoCacheLock );
|
||
}
|
||
|
||
UNLOCK_GENERAL();
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// 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" ));
|
||
|
||
|
||
// 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 DWORD Flag,
|
||
IN DWORD AcceptLocalCacheTime OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
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:
|
||
|
||
Flag -- flag; read order and IP
|
||
NIFLAG_GET_LOCAL_ADDRS
|
||
NIFLAG_FORCE_REGISTRY_READ
|
||
NIFLAG_READ_RESOLVER_FIRST
|
||
NIFLAG_READ_RESOLVER
|
||
NIFLAG_READ_PROCESS_CACHE
|
||
|
||
AcceptLocalCacheTime -- acceptable cache time on in process copy
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO pnetInfo = NULL;
|
||
PDNS_NETINFO poldNetInfo = NULL;
|
||
BOOL fcacheLock = FALSE;
|
||
BOOL fbuildLock = FALSE;
|
||
BOOL fcacheable = TRUE;
|
||
|
||
DNSDBG( NETINFO, (
|
||
"NetInfo_Get( %08x, %d )\n",
|
||
Flag,
|
||
AcceptLocalCacheTime ));
|
||
|
||
//
|
||
// init netinfo locks\caching
|
||
//
|
||
|
||
if ( !InitNetworkInfo() )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// get netinfo from one of several sources
|
||
// try
|
||
// - very recent local cached copy
|
||
// - RPC copy from resolver
|
||
// - build new
|
||
//
|
||
// note the locking model
|
||
// two SEPARATE locks
|
||
// - cache lock, for very quick, very local access
|
||
// to cached copy
|
||
// - build lock, for remote process access to cached (resolver)
|
||
// or newly built netinfo
|
||
//
|
||
// the locking hierarchy
|
||
// - build lock
|
||
// - cache lock (maybe taken inside build lock)
|
||
//
|
||
//
|
||
// Locking implementation note:
|
||
//
|
||
// The reason for the two locks is that when calling down for netinfo
|
||
// build it is possible to have a circular dependency.
|
||
//
|
||
// Here's the deadlock scenario if we have a single lock handling
|
||
// build and caching:
|
||
// - call into resolver and down to iphlpapi
|
||
// - iphlpapi RPC's into MPR (router service)
|
||
// - RtrMgr calls GetHostByName() which ends up in a
|
||
// iphlpapi!GetBestInterface call which in turn calls
|
||
// Mprapi!IsRouterRunning (which is an RPC to mprdim).
|
||
// - 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.
|
||
// - Demand-dial disconnect is waiting for ppp to finish graceful
|
||
// termination.
|
||
// - PPP is waiting for dns to return from DnsSetConfigDword
|
||
// - DnsSetConfigDword, sets, alerts the cache, then calls
|
||
// NetInfo_MarkDirty()
|
||
// - NetInfo_MarkDirty() is waiting on CS to access the netinfo global.
|
||
//
|
||
// Now, this could be avoided by changing MarkDirty() to safely set some
|
||
// dirty bit (interlock). The build function would have to check the bit
|
||
// and go down again if it was set.
|
||
//
|
||
// However, there'd still be a chance that the call down to iphlpapi, could
|
||
// depend under some odd circumstance on some service that came back through
|
||
// the resolver. And the bottom line is that the real distinction is not
|
||
// between caching and marking cache dirty. It's between completely local
|
||
// cache get\set\clear activity, which can be safely overloaded on the general CS,
|
||
// AND the longer time, multi-service dependent building operation. So
|
||
// separate CS for both is correct.
|
||
//
|
||
|
||
|
||
if ( !(Flag & NIFLAG_FORCE_REGISTRY_READ)
|
||
&&
|
||
!g_DnsTestMode )
|
||
{
|
||
//
|
||
// RPC to resolver
|
||
//
|
||
|
||
if ( Flag & NIFLAG_READ_RESOLVER_FIRST )
|
||
{
|
||
// 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
|
||
|
||
fbuildLock = LOCK_NETINFO_BUILD();
|
||
if ( !fbuildLock )
|
||
{
|
||
goto Unlock;
|
||
}
|
||
|
||
pnetInfo = UpdateDnsConfig();
|
||
if ( pnetInfo )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"Netinfo read from resolver.\n" ));
|
||
goto CacheCopy;
|
||
}
|
||
}
|
||
|
||
//
|
||
// use in-process cached copy?
|
||
//
|
||
|
||
if ( Flag & NIFLAG_READ_PROCESS_CACHE )
|
||
{
|
||
DWORD timeout = NETINFO_CACHE_TIMEOUT;
|
||
|
||
LOCK_NETINFO_CACHE();
|
||
fcacheLock = TRUE;
|
||
|
||
if ( AcceptLocalCacheTime )
|
||
{
|
||
timeout = AcceptLocalCacheTime;
|
||
}
|
||
|
||
// check if valid copy cached in process
|
||
|
||
if ( g_pNetInfo &&
|
||
(g_pNetInfo->TimeStamp + timeout > Dns_GetCurrentTimeInSeconds()) )
|
||
{
|
||
pnetInfo = NetInfo_Copy( g_pNetInfo );
|
||
if ( pnetInfo )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"Netinfo found in process cache.\n" ));
|
||
goto Unlock;
|
||
}
|
||
}
|
||
|
||
UNLOCK_NETINFO_CACHE();
|
||
fcacheLock = FALSE;
|
||
}
|
||
|
||
//
|
||
// last chance on resolver
|
||
//
|
||
|
||
if ( !fbuildLock && (Flag & NIFLAG_READ_RESOLVER) )
|
||
{
|
||
fbuildLock = LOCK_NETINFO_BUILD();
|
||
if ( !fbuildLock )
|
||
{
|
||
goto Unlock;
|
||
}
|
||
|
||
pnetInfo = UpdateDnsConfig();
|
||
if ( pnetInfo )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"Netinfo read from resolver.\n" ));
|
||
goto CacheCopy;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// build fresh network info
|
||
//
|
||
|
||
DNS_ASSERT( !fcacheLock );
|
||
|
||
if ( !fbuildLock )
|
||
{
|
||
fbuildLock = LOCK_NETINFO_BUILD();
|
||
if ( !fbuildLock )
|
||
{
|
||
goto Unlock;
|
||
}
|
||
}
|
||
|
||
fcacheable = (Flag & NIFLAG_GET_LOCAL_ADDRS);
|
||
|
||
pnetInfo = NetInfo_Build( fcacheable );
|
||
if ( !pnetInfo )
|
||
{
|
||
goto Unlock;
|
||
}
|
||
|
||
CacheCopy:
|
||
|
||
//
|
||
// update cached copy
|
||
// - but not if built without local IPs;
|
||
// resolver copy always contains local IPs
|
||
//
|
||
|
||
if ( fcacheable )
|
||
{
|
||
if ( !fcacheLock )
|
||
{
|
||
LOCK_NETINFO_CACHE();
|
||
fcacheLock = TRUE;
|
||
}
|
||
poldNetInfo = g_pNetInfo;
|
||
g_pNetInfo = NetInfo_Copy( pnetInfo );
|
||
}
|
||
|
||
|
||
Unlock:
|
||
|
||
if ( fcacheLock )
|
||
{
|
||
UNLOCK_NETINFO_CACHE();
|
||
}
|
||
if ( fbuildLock )
|
||
{
|
||
UNLOCK_NETINFO_BUILD();
|
||
}
|
||
|
||
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" ));
|
||
|
||
|
||
//
|
||
// init netinfo locks\caching
|
||
//
|
||
|
||
if ( !InitNetworkInfo() )
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// 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_CACHE();
|
||
|
||
pold = g_pNetInfo;
|
||
g_pNetInfo = NULL;
|
||
|
||
UNLOCK_NETINFO_CACHE();
|
||
|
||
NetInfo_Free( pold );
|
||
}
|
||
|
||
|
||
|
||
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
|
||
(currently ignored -- always get all the info)
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
REG_SESSION regSession;
|
||
PREG_SESSION pregSession = NULL;
|
||
PDNS_NETINFO pnetInfo = NULL;
|
||
PDNS_ADAPTER pdnsAdapter = NULL;
|
||
DNS_STATUS status = NO_ERROR;
|
||
DWORD count;
|
||
DWORD createdAdapterCount = 0;
|
||
BOOL fuseIp;
|
||
PIP_ADAPTER_ADDRESSES padapterList = NULL;
|
||
PIP_ADAPTER_ADDRESSES padapter = NULL;
|
||
DWORD value;
|
||
PREG_GLOBAL_INFO pregInfo = NULL;
|
||
REG_GLOBAL_INFO regInfo;
|
||
REG_ADAPTER_INFO regAdapterInfo;
|
||
DWORD flag;
|
||
BOOL fhaveDnsServers = FALSE;
|
||
|
||
|
||
DNSDBG( TRACE, ( "\n\n\nNetInfo_Build()\n\n" ));
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
//
|
||
// get adapter\address info from IP help
|
||
//
|
||
// note: always getting 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
|
||
//
|
||
|
||
flag = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST;
|
||
#if 0
|
||
if ( !fGetIpAddrs )
|
||
{
|
||
flag |= GAA_FLAG_SKIP_UNICAST;
|
||
}
|
||
#endif
|
||
|
||
padapterList = IpHelp_GetAdaptersAddresses(
|
||
PF_UNSPEC,
|
||
flag );
|
||
if ( !padapterList )
|
||
{
|
||
status = GetLastError();
|
||
DNS_ASSERT( status != NO_ERROR );
|
||
goto Cleanup;
|
||
}
|
||
|
||
// count up the active adapters
|
||
|
||
padapter = padapterList;
|
||
count = 0;
|
||
|
||
while ( padapter )
|
||
{
|
||
count++;
|
||
padapter = padapter->Next;
|
||
}
|
||
|
||
//
|
||
// allocate net info blob
|
||
// allocate DNS server IP array
|
||
//
|
||
|
||
pnetInfo = NetInfo_Alloc( count );
|
||
if ( !pnetInfo )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// loop through adapters -- build network info for each
|
||
//
|
||
|
||
padapter = padapterList;
|
||
|
||
while ( padapter )
|
||
{
|
||
DWORD adapterFlags = 0;
|
||
PWSTR pnameAdapter = NULL;
|
||
PWSTR padapterDomainName = NULL;
|
||
PDNS_ADDR_ARRAY pserverArray = NULL;
|
||
PDNS_ADDR_ARRAY plocalArray = NULL;
|
||
|
||
//
|
||
// read adapter registry info
|
||
//
|
||
// DCR: can skip adapter domain name read
|
||
// it's in IP help adapter, just need policy override
|
||
// DCR: can skip DDNS read, and register read
|
||
// again, except for policy overrides
|
||
//
|
||
// DCR: could just have an "ApplyPolicyOverridesToAdapterInfo()" sort
|
||
// of function and get the rest from
|
||
//
|
||
|
||
pnameAdapter = Dns_StringCopyAllocate(
|
||
padapter->AdapterName,
|
||
0,
|
||
DnsCharSetAnsi,
|
||
DnsCharSetUnicode );
|
||
if ( !pnameAdapter )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
|
||
status = Reg_ReadAdapterInfo(
|
||
pnameAdapter,
|
||
pregSession,
|
||
& regInfo, // policy adapter info
|
||
& regAdapterInfo // receives reg info read
|
||
);
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
status = Reg_DefaultAdapterInfo(
|
||
& regAdapterInfo,
|
||
& regInfo,
|
||
padapter );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
goto Skip;
|
||
}
|
||
}
|
||
|
||
// translate results into flags
|
||
|
||
if ( regAdapterInfo.fRegistrationEnabled )
|
||
{
|
||
adapterFlags |= AINFO_FLAG_REGISTER_IP_ADDRESSES;
|
||
}
|
||
if ( regAdapterInfo.fRegisterAdapterName )
|
||
{
|
||
adapterFlags |= AINFO_FLAG_REGISTER_DOMAIN_NAME;
|
||
}
|
||
|
||
// use domain name?
|
||
// - if disable on per adapter basis, then it's dead
|
||
|
||
if ( regAdapterInfo.fQueryAdapterName )
|
||
{
|
||
padapterDomainName = regAdapterInfo.pszAdapterDomainName;
|
||
regAdapterInfo.pszAdapterDomainName = NULL;
|
||
}
|
||
|
||
// DCR: could get DDNS and registration for adapter
|
||
|
||
// set flag on DHCP adapters
|
||
|
||
if ( padapter->Flags & IP_ADAPTER_DHCP_ENABLED )
|
||
{
|
||
adapterFlags |= AINFO_FLAG_IS_DHCP_CFG_ADAPTER;
|
||
}
|
||
|
||
//
|
||
// get adapter's IP addresses
|
||
//
|
||
|
||
fuseIp = fGetIpAddrs;
|
||
if ( fuseIp )
|
||
{
|
||
status = IpHelp_ReadAddrsFromList(
|
||
padapter->FirstUnicastAddress,
|
||
TRUE, // unicast addrs
|
||
0, // no screening
|
||
0, // no screening
|
||
& plocalArray, // local addrs
|
||
NULL, // IP6 only
|
||
NULL, // IP4 only
|
||
NULL, // no IP6 count
|
||
NULL // no IP4 count
|
||
);
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
//
|
||
// get per-adapter information from the iphlpapi.dll.
|
||
// -- autonet
|
||
//
|
||
// FIX6: do we need autonet info?
|
||
|
||
pserverArray = NULL;
|
||
|
||
status = IpHelp_GetPerAdapterInfo(
|
||
padapter->Index,
|
||
& pperAdapterInfo );
|
||
|
||
if ( status == NO_ERROR )
|
||
{
|
||
if ( pperAdapterInfo->AutoconfigEnabled &&
|
||
pperAdapterInfo->AutoconfigActive )
|
||
{
|
||
adapterFlags |= AINFO_FLAG_IS_AUTONET_ADAPTER;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// build DNS list
|
||
//
|
||
|
||
if ( padapter->FirstDnsServerAddress )
|
||
{
|
||
status = IpHelp_ReadAddrsFromList(
|
||
padapter->FirstDnsServerAddress,
|
||
FALSE, // not unicast addrs
|
||
0, // no screening
|
||
0, // no screening
|
||
& pserverArray, // get combined list
|
||
NULL, // no IP6 only
|
||
NULL, // no IP4 only
|
||
NULL, // no IP6 count
|
||
NULL // no IP4 count
|
||
);
|
||
if ( status != NO_ERROR )
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
fhaveDnsServers = TRUE;
|
||
}
|
||
else
|
||
{
|
||
#if 0
|
||
//
|
||
// note: this feature doesn't work very well
|
||
// it kicks in when cable unplugged and get into auto-net
|
||
// scenario ... and then can bring in an unconfigured
|
||
// DNS server and give us long timeouts
|
||
//
|
||
// DCR: pointing to local DNS server
|
||
// a good approach would be to point to local DNS on ALL
|
||
// adapters when we fail to find ANY DNS servers at all
|
||
//
|
||
|
||
//
|
||
// if no DNS servers found -- use loopback if on DNS server
|
||
//
|
||
|
||
if ( g_IsDnsServer )
|
||
{
|
||
pserverArray = DnsAddrArray_Create( 1 );
|
||
if ( !pserverArray )
|
||
{
|
||
goto Skip;
|
||
}
|
||
DnsAddrArray_InitSingleWithIp4(
|
||
pserverArray,
|
||
DNS_NET_ORDER_LOOPBACK );
|
||
}
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// 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
|
||
//
|
||
// DCR: no failure case on adapter create failure???
|
||
//
|
||
// DCR: when do we need non-server adapters? for mcast?
|
||
//
|
||
// DCR: we could create Adapter name in unicode (above) then
|
||
// just copy it in;
|
||
// DCR: could preserve adapter domain name in blob, and NULL
|
||
// out the string in regAdapterInfo
|
||
//
|
||
|
||
if ( pserverArray || plocalArray )
|
||
{
|
||
PDNS_ADAPTER pnewAdapter = &pnetInfo->AdapterArray[ createdAdapterCount ];
|
||
|
||
AdapterInfo_Init(
|
||
pnewAdapter,
|
||
TRUE, // zero init
|
||
adapterFlags,
|
||
pnameAdapter,
|
||
padapterDomainName,
|
||
plocalArray,
|
||
pserverArray
|
||
);
|
||
|
||
pnewAdapter->InterfaceIndex = padapter->IfIndex;
|
||
|
||
pnetInfo->AdapterCount = ++createdAdapterCount;
|
||
|
||
pnameAdapter = NULL;
|
||
padapterDomainName = NULL;
|
||
plocalArray = NULL;
|
||
pserverArray = NULL;
|
||
}
|
||
|
||
Skip:
|
||
//
|
||
// cleanup adapter specific data
|
||
//
|
||
// note: no free of pserverArray, it IS the
|
||
// ptempArray buffer that we free at the end
|
||
//
|
||
|
||
Reg_FreeAdapterInfo(
|
||
®AdapterInfo,
|
||
FALSE // don't free blob, it is on stack
|
||
);
|
||
|
||
if ( pnameAdapter );
|
||
{
|
||
FREE_HEAP( pnameAdapter );
|
||
}
|
||
if ( padapterDomainName );
|
||
{
|
||
FREE_HEAP( padapterDomainName );
|
||
}
|
||
if ( pserverArray );
|
||
{
|
||
DnsAddrArray_Free( pserverArray );
|
||
}
|
||
if ( plocalArray )
|
||
{
|
||
DnsAddrArray_Free( plocalArray );
|
||
}
|
||
|
||
// get next adapter
|
||
// reset status, so failure on the last adapter is not
|
||
// seen as global failure
|
||
|
||
padapter = padapter->Next;
|
||
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// no DNS servers?
|
||
// - use loopback if we are on MS DNS
|
||
// - otherwise note netinfo useless for lookup
|
||
//
|
||
// when self-pointing:
|
||
// - setup all adapters so we preserve adapter domain names for lookup
|
||
// - mark adapters as auto-loopback; send code will then avoid continuing
|
||
// query on other adapters
|
||
//
|
||
// note, i specifically choose this approach rather than configuring on any
|
||
// serverless adapter even if other adapters have DNS servers
|
||
// this avoids two problems:
|
||
// - server is poorly configured but CAN answer and fast local resolution
|
||
// blocks resolution through real DNS servers
|
||
// - network edge scenarios where DNS may be out-facing, but DNS client
|
||
// resolution may be intentionally desired to be only internal (admin network)
|
||
// in both cases i don't want to "pop" local DNS into the mix when it is unintended.
|
||
// when it is intended the easy workaround is to configure it explicitly
|
||
//
|
||
|
||
if ( !fhaveDnsServers )
|
||
{
|
||
if ( g_IsDnsServer )
|
||
{
|
||
DWORD i;
|
||
|
||
for ( i=0; i<pnetInfo->AdapterCount; i++ )
|
||
{
|
||
PDNS_ADAPTER padapt = NetInfo_GetAdapterByIndex( pnetInfo, i );
|
||
PDNS_ADDR_ARRAY pserverArray = NULL;
|
||
|
||
pserverArray = DnsAddrArray_Create( 1 );
|
||
if ( !pserverArray )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
DnsAddrArray_InitSingleWithIp4(
|
||
pserverArray,
|
||
DNS_NET_ORDER_LOOPBACK );
|
||
|
||
padapt->pDnsAddrs = pserverArray;
|
||
padapt->InfoFlags &= ~AINFO_FLAG_IGNORE_ADAPTER;
|
||
padapt->InfoFlags |= AINFO_FLAG_SERVERS_AUTO_LOOPBACK;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pnetInfo->InfoFlags |= NINFO_FLAG_NO_DNS_SERVERS;
|
||
}
|
||
}
|
||
|
||
//
|
||
// 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
|
||
);
|
||
if ( !pnetInfo->pSearchList )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
//
|
||
// host and domain name info
|
||
//
|
||
|
||
pnetInfo->pszDomainName = Dns_CreateStringCopy_W( regInfo.pszPrimaryDomainName );
|
||
pnetInfo->pszHostName = Dns_CreateStringCopy_W( regInfo.pszHostName );
|
||
|
||
// timestamp
|
||
|
||
pnetInfo->TimeStamp = Dns_GetCurrentTimeInSeconds();
|
||
|
||
//
|
||
// set default server priorities
|
||
//
|
||
|
||
NetInfo_ResetServerPriorities( pnetInfo, FALSE );
|
||
|
||
|
||
Cleanup:
|
||
|
||
// free allocated reg info
|
||
|
||
Reg_FreeGlobalInfo(
|
||
pregInfo,
|
||
FALSE // don't free blob, it is on stack
|
||
);
|
||
|
||
if ( padapterList )
|
||
{
|
||
FREE_HEAP( padapterList );
|
||
}
|
||
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 );
|
||
}
|
||
|
||
IF_DNSDBG( NETINFO2 )
|
||
{
|
||
DnsDbg_NetworkInfo(
|
||
"New Netinfo:",
|
||
pnetInfo );
|
||
}
|
||
|
||
DNSDBG( TRACE, (
|
||
"\nLeave: NetInfo_Build()\n\n\n"
|
||
"\treturning fresh built network info (%p)\n",
|
||
pnetInfo ));
|
||
|
||
return( pnetInfo );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Local address list
|
||
//
|
||
|
||
DWORD
|
||
netinfo_AddrFlagForConfigFlag(
|
||
IN DWORD ConfigFlag
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build the DNS_ADDR flag for a given config flag.
|
||
|
||
Arguments:
|
||
|
||
ConfigFlag -- config flag we're given.
|
||
|
||
Return Value:
|
||
|
||
Flag in DNS_ADDR. Note this covers only the bits in DNSADDR_FLAG_TYPE_MASK
|
||
not the entire flag.
|
||
|
||
--*/
|
||
{
|
||
DWORD flag = 0;
|
||
|
||
if ( ConfigFlag & DNS_CONFIG_FLAG_ADDR_PUBLIC )
|
||
{
|
||
flag |= DNSADDR_FLAG_PUBLIC;
|
||
}
|
||
|
||
if ( ConfigFlag & DNS_CONFIG_FLAG_ADDR_CLUSTER )
|
||
{
|
||
flag |= DNSADDR_FLAG_TRANSIENT;
|
||
}
|
||
|
||
return flag;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
netinfo_LocalAddrScreen(
|
||
IN PDNS_ADDR pAddr,
|
||
IN PDNS_ADDR pScreenAddr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check DNS_ADDR against screening critera for local addr build.
|
||
|
||
Arguments:
|
||
|
||
pAddr -- address to screen
|
||
|
||
pScreenAddr -- screening info
|
||
|
||
Return Value:
|
||
|
||
TRUE if local addr passes screen.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
DWORD family = DnsAddr_Family( pScreenAddr );
|
||
DWORD flags;
|
||
|
||
// screen family
|
||
|
||
if ( family &&
|
||
family != DnsAddr_Family(pAddr) )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
// screen flags
|
||
// - exact match on address type flag bits
|
||
|
||
return ( (pAddr->Flags & pScreenAddr->DnsAddrFlagScreeningMask)
|
||
== pScreenAddr->Flags);
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
netinfo_ReadLocalAddrs(
|
||
IN OUT PDNS_ADDR_ARRAY pAddrArray,
|
||
IN PDNS_NETINFO pNetInfo,
|
||
IN PDNS_ADAPTER pSingleAdapter, OPTIONAL
|
||
IN OUT PDNS_ADDR pScreenAddr,
|
||
IN DWORD AddrFlags,
|
||
IN DWORD AddrMask,
|
||
IN DWORD ReadCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create IP array of DNS servers from network info.
|
||
|
||
Arguments:
|
||
|
||
pAddrArray -- local address array being built
|
||
|
||
pNetInfo -- DNS net adapter list to convert
|
||
|
||
pSingleAdapter -- just do this one adapter
|
||
|
||
pScreenAddr -- address screening blob;
|
||
note: there's no true OUT info, but the screen addr
|
||
is altered to match AddrFlags
|
||
|
||
AddrFlags -- addr flag we're interested in
|
||
|
||
ReadCount -- count to read
|
||
1 -- just one
|
||
MAXDWORD -- all
|
||
0 -- all on second pass
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if successful.
|
||
Otherwise error code from add.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADDR_ARRAY parray = NULL;
|
||
PDNS_ADAPTER padapter;
|
||
DNS_STATUS status = NO_ERROR;
|
||
DWORD dupFlag = 0;
|
||
DWORD screenMask;
|
||
DWORD iter;
|
||
|
||
DNSDBG( TRACE, (
|
||
"netinfo_ReadLocalAddrs( %p, %p, %p, %08x, %08x, %d )\n",
|
||
pNetInfo,
|
||
pSingleAdapter,
|
||
pScreenAddr,
|
||
AddrFlags,
|
||
AddrMask,
|
||
ReadCount ));
|
||
|
||
//
|
||
// get DNS_ADDR flag for the address type we're reading
|
||
//
|
||
// note we have the classic and\or problem
|
||
// the addresses are denoted by two flags (from iphelp):
|
||
// DNSADDR_FLAG_PUBLIC
|
||
// DNSADDR_FLAG_TRANSIENT
|
||
//
|
||
// but we need both flags and mask to determine all the possible gatherings
|
||
// we want to do
|
||
//
|
||
// right now the DNS_CONFIG_FLAG_X are ORd together to get UNIONS of addresses
|
||
// we are willing to accept, but we go through the list multiple times to build
|
||
// the list favoring the public over private, non-cluster over cluster
|
||
//
|
||
// so currently when say you want DNS_CONFIG_PUBLIC you mean public and not-cluster;
|
||
// ditto for private; on the other hand when you say DNS_CONFIG_CLUSTER you are
|
||
// asking for all cluster (though we could screen on whether PUBLIC, PRIVATE both or
|
||
// neither were specified
|
||
//
|
||
|
||
pScreenAddr->Flags = netinfo_AddrFlagForConfigFlag( AddrFlags );
|
||
|
||
screenMask = DNSADDR_FLAG_TYPE_MASK;
|
||
if ( AddrMask != 0 )
|
||
{
|
||
screenMask = netinfo_AddrFlagForConfigFlag( AddrMask );
|
||
}
|
||
pScreenAddr->DnsAddrFlagScreeningMask = screenMask;
|
||
|
||
//
|
||
// read count
|
||
// = 0 means second pass on list
|
||
// -> read all, but do full duplicate screen to skip the
|
||
// addresses read on the first pass
|
||
|
||
if ( ReadCount == 0 )
|
||
{
|
||
ReadCount = MAXDWORD;
|
||
dupFlag = DNSADDR_MATCH_ALL;
|
||
}
|
||
|
||
//
|
||
// loop through all adapters
|
||
//
|
||
|
||
for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
|
||
{
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
|
||
|
||
if ( !pSingleAdapter ||
|
||
pSingleAdapter == padapter )
|
||
{
|
||
status = DnsAddrArray_AppendArrayEx(
|
||
pAddrArray,
|
||
padapter->pLocalAddrs,
|
||
ReadCount, // read address count
|
||
0, // family check handled by screening
|
||
dupFlag,
|
||
netinfo_LocalAddrScreen,
|
||
pScreenAddr
|
||
);
|
||
}
|
||
//DNS_ASSERT( status == NO_ERROR );
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
PADDR_ARRAY
|
||
NetInfo_CreateLocalAddrArray(
|
||
IN PDNS_NETINFO pNetInfo,
|
||
IN PWSTR pwsAdapterName, OPTIONAL
|
||
IN PDNS_ADAPTER pAdapter, OPTIONAL
|
||
IN DWORD Family, OPTIONAL
|
||
IN DWORD AddrFlags OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create IP array of DNS servers from network info.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- DNS net adapter list to convert
|
||
|
||
pwsAdapterName -- specific adapter; NULL for all adapters
|
||
|
||
pAdapter -- specific adapter; NULL for all adapters
|
||
|
||
Family -- required specific address family; 0 for any family
|
||
|
||
AddrFlags -- address selection flags
|
||
DNS_CONFIG_FLAG_INCLUDE_CLUSTER
|
||
|
||
AddrFlagsMask -- mask on selecting flags
|
||
|
||
Return Value:
|
||
|
||
Ptr to IP array, if successful
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PADDR_ARRAY parray = NULL;
|
||
DWORD iter;
|
||
DWORD countAddrs = 0;
|
||
PDNS_ADAPTER padapter;
|
||
PDNS_ADAPTER padapterSingle = NULL;
|
||
DNS_STATUS status = NO_ERROR;
|
||
DNS_ADDR screenAddr;
|
||
|
||
DNSDBG( TRACE, (
|
||
"NetInfo_CreateLocalAddrArray( %p, %S, %p, %d, %08x )\n",
|
||
pNetInfo,
|
||
pwsAdapterName,
|
||
pAdapter,
|
||
Family,
|
||
AddrFlags ));
|
||
|
||
//
|
||
// get count
|
||
//
|
||
|
||
if ( ! pNetInfo )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
padapterSingle = pAdapter;
|
||
if ( pwsAdapterName && !padapterSingle )
|
||
{
|
||
padapterSingle = NetInfo_GetAdapterByName( pNetInfo, pwsAdapterName );
|
||
if ( !padapterSingle )
|
||
{
|
||
goto Done;
|
||
}
|
||
}
|
||
|
||
//
|
||
// setup screening addr
|
||
//
|
||
// if not address flag -- get all types
|
||
//
|
||
|
||
if ( AddrFlags == 0 )
|
||
{
|
||
AddrFlags = (DWORD)(-1);
|
||
}
|
||
|
||
RtlZeroMemory( &screenAddr, sizeof(screenAddr) );
|
||
screenAddr.Sockaddr.sa_family = (WORD)Family;
|
||
|
||
//
|
||
// count addrs
|
||
//
|
||
// DCR: could count with based on addr info
|
||
//
|
||
|
||
for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
|
||
{
|
||
padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
|
||
|
||
if ( !padapterSingle ||
|
||
padapterSingle == padapter )
|
||
{
|
||
countAddrs += DnsAddrArray_GetFamilyCount(
|
||
padapter->pLocalAddrs,
|
||
Family );
|
||
}
|
||
}
|
||
|
||
//
|
||
// allocate required array
|
||
//
|
||
|
||
parray = DnsAddrArray_Create( countAddrs );
|
||
if ( !parray )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Done;
|
||
}
|
||
DNS_ASSERT( parray->MaxCount == countAddrs );
|
||
|
||
|
||
//
|
||
// read addrs "in order"
|
||
//
|
||
// historically gethostbyname() presented addrs
|
||
// - one from each adapter
|
||
// - then the rest from all adapters
|
||
//
|
||
// we preserve this, plus order by type
|
||
// - public DNS_ELIGIBLE first
|
||
// - private (autonet, IP6 local scope stuff)
|
||
// - cluster\transient last
|
||
//
|
||
|
||
//
|
||
// public (DNS_ELIGIBLE) addrs
|
||
// - screen on all flags, specifically don't pick up public cluster addrs
|
||
//
|
||
|
||
if ( AddrFlags & DNS_CONFIG_FLAG_ADDR_PUBLIC )
|
||
{
|
||
// read first "public" addr of each (or single) adapter
|
||
|
||
status = netinfo_ReadLocalAddrs(
|
||
parray,
|
||
pNetInfo,
|
||
padapterSingle,
|
||
& screenAddr,
|
||
DNS_CONFIG_FLAG_ADDR_PUBLIC,
|
||
0, // exact match on all flags
|
||
1 // read only one address
|
||
);
|
||
|
||
// read the rest of "public" addrs
|
||
|
||
status = netinfo_ReadLocalAddrs(
|
||
parray,
|
||
pNetInfo,
|
||
padapterSingle,
|
||
& screenAddr,
|
||
DNS_CONFIG_FLAG_ADDR_PUBLIC,
|
||
0, // exact match on all flags
|
||
0 // read the rest
|
||
);
|
||
}
|
||
|
||
//
|
||
// private (non-DNS-publish) addrs (autonet, IP6 local, sitelocal, etc.)
|
||
// - screen on all flags, specifically don't pick up private cluster addrs
|
||
//
|
||
|
||
if ( AddrFlags & DNS_CONFIG_FLAG_ADDR_PRIVATE )
|
||
{
|
||
status = netinfo_ReadLocalAddrs(
|
||
parray,
|
||
pNetInfo,
|
||
padapterSingle,
|
||
& screenAddr,
|
||
DNS_CONFIG_FLAG_ADDR_PRIVATE,
|
||
0, // exact match on all flags
|
||
MAXDWORD // read all addrs
|
||
);
|
||
}
|
||
|
||
//
|
||
// cluster at end
|
||
// - only screen on cluster flag as public flag may
|
||
// also be set\clear
|
||
//
|
||
|
||
if ( AddrFlags & DNS_CONFIG_FLAG_ADDR_CLUSTER )
|
||
{
|
||
status = netinfo_ReadLocalAddrs(
|
||
parray,
|
||
pNetInfo,
|
||
padapterSingle,
|
||
& screenAddr,
|
||
DNS_CONFIG_FLAG_ADDR_CLUSTER,
|
||
DNS_CONFIG_FLAG_ADDR_CLUSTER, // any cluster match
|
||
MAXDWORD // read all addrs
|
||
);
|
||
}
|
||
|
||
Done:
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
SetLastError( status );
|
||
}
|
||
|
||
return( parray );
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// Local address list presentation
|
||
//
|
||
|
||
PDNS_ADDR_ARRAY
|
||
NetInfo_GetLocalAddrArray(
|
||
IN PDNS_NETINFO pNetInfo,
|
||
IN PWSTR pwsAdapterName, OPTIONAL
|
||
IN DWORD AddrFamily, OPTIONAL
|
||
IN DWORD AddrFlags, OPTIONAL
|
||
IN BOOL fForce
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get local addrs as array.
|
||
|
||
This is a combination NetInfo_Get\ConvertToLocalAddrArray routine.
|
||
It's purpose is to simplify getting local address info, while avoiding
|
||
costly NetInfo rebuilds where they are unnecessary.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- existing netinfo to use
|
||
|
||
pwsAdapterName -- specific adapter name; NULL for all adapters
|
||
|
||
AddrFamily -- specific address family; 0 for all
|
||
|
||
AddrFlags -- flags to indicate addrs to consider
|
||
DNS_CONFIG_FLAG_INCLUDE_CLUSTER
|
||
|
||
fForce -- force reread from registry
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO pnetInfo = NULL;
|
||
PADDR_ARRAY parray = NULL;
|
||
DNS_STATUS status = NO_ERROR;
|
||
|
||
DNSDBG( TRACE, (
|
||
"NetInfo_GetLocalAddrArray()\n"
|
||
"\tpnetinfo = %p\n"
|
||
"\tadapter = %S\n"
|
||
"\tfamily = %d\n"
|
||
"\tflags = %08x\n"
|
||
"\tforce = %d\n",
|
||
pNetInfo,
|
||
pwsAdapterName,
|
||
AddrFamily,
|
||
AddrFlags,
|
||
fForce
|
||
));
|
||
|
||
//
|
||
// get network info to make list from
|
||
// - if force, full reread
|
||
// - otherwise gethostbyname() scenario
|
||
// - accept local caching for very short interval just for perf
|
||
// - accept resolver
|
||
//
|
||
// DCR: force first gethostbyname() call to resolver\registry?
|
||
// have to define "first", in a way that's different from netinfo()
|
||
// in last second
|
||
//
|
||
|
||
pnetInfo = pNetInfo;
|
||
|
||
if ( !pnetInfo )
|
||
{
|
||
DWORD getFlag = NIFLAG_GET_LOCAL_ADDRS;
|
||
DWORD timeout;
|
||
|
||
if ( fForce )
|
||
{
|
||
getFlag |= NIFLAG_FORCE_REGISTRY_READ;
|
||
timeout = 0;
|
||
}
|
||
else
|
||
{
|
||
getFlag |= NIFLAG_READ_RESOLVER;
|
||
getFlag |= NIFLAG_READ_PROCESS_CACHE;
|
||
timeout = 1;
|
||
}
|
||
|
||
pnetInfo = NetInfo_Get(
|
||
getFlag,
|
||
timeout
|
||
);
|
||
if ( !pnetInfo )
|
||
{
|
||
status = DNS_ERROR_NO_TCPIP;
|
||
goto Done;
|
||
}
|
||
}
|
||
|
||
//
|
||
// cluster filter info
|
||
// -- check environment variable
|
||
//
|
||
// DCR: once RnR no longer using myhostent() for gethostbyname()
|
||
// then can remove
|
||
|
||
if ( g_IsServer &&
|
||
(AddrFlags & DNS_CONFIG_FLAG_READ_CLUSTER_ENVAR) &&
|
||
!(AddrFlags & DNS_CONFIG_FLAG_ADDR_CLUSTER) )
|
||
{
|
||
ENVAR_DWORD_INFO filterInfo;
|
||
|
||
Reg_ReadDwordEnvar(
|
||
RegIdFilterClusterIp,
|
||
&filterInfo );
|
||
|
||
if ( !filterInfo.fFound ||
|
||
!filterInfo.Value )
|
||
{
|
||
AddrFlags |= DNS_CONFIG_FLAG_ADDR_CLUSTER;
|
||
}
|
||
}
|
||
|
||
//
|
||
// convert network info to IP4_ARRAY
|
||
//
|
||
|
||
parray = NetInfo_CreateLocalAddrArray(
|
||
pnetInfo,
|
||
pwsAdapterName,
|
||
NULL, // no specific adapter ptr
|
||
AddrFamily,
|
||
AddrFlags
|
||
);
|
||
|
||
if ( !parray )
|
||
{
|
||
status = GetLastError();
|
||
goto Done;
|
||
}
|
||
|
||
// if no IPs found, return
|
||
|
||
if ( parray->AddrCount == 0 )
|
||
{
|
||
DNS_PRINT((
|
||
"NetInfo_GetLocalAddrArray() failed: no addrs found\n"
|
||
"\tstatus = %d\n" ));
|
||
status = DNS_ERROR_NO_TCPIP;
|
||
goto Done;
|
||
}
|
||
|
||
IF_DNSDBG( NETINFO )
|
||
{
|
||
DNS_PRINT(( "Leaving Netinfo_GetLocalAddrArray()\n" ));
|
||
DnsDbg_DnsAddrArray(
|
||
"Local addr list",
|
||
"server",
|
||
parray );
|
||
}
|
||
|
||
Done:
|
||
|
||
// free netinfo built here
|
||
|
||
if ( pnetInfo != pNetInfo )
|
||
{
|
||
NetInfo_Free( pnetInfo );
|
||
}
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
FREE_HEAP( parray );
|
||
parray = NULL;
|
||
SetLastError( status );
|
||
}
|
||
|
||
return( parray );
|
||
}
|
||
|
||
|
||
|
||
PIP4_ARRAY
|
||
NetInfo_GetLocalAddrArrayIp4(
|
||
IN PWSTR pwsAdapterName, OPTIONAL
|
||
IN DWORD Flags,
|
||
IN BOOL fForce
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get DNS server list as IP array.
|
||
|
||
Arguments:
|
||
|
||
pwsAdapterName -- specific adapter name; NULL for all adapters
|
||
|
||
Flags -- flags to indicate addrs to consider
|
||
DNS_CONFIG_FLAG_X
|
||
|
||
fForce -- force reread from registry
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
PADDR_ARRAY parray;
|
||
PIP4_ARRAY parray4 = NULL;
|
||
DNS_STATUS status = NO_ERROR;
|
||
|
||
DNSDBG( TRACE, ( "NetInfo_GetLocalAddrArrayIp4()\n" ));
|
||
|
||
//
|
||
// get DNS server list
|
||
//
|
||
|
||
parray = NetInfo_GetLocalAddrArray(
|
||
NULL, // no existing netinfo
|
||
pwsAdapterName,
|
||
AF_INET,
|
||
Flags,
|
||
fForce );
|
||
if ( !parray )
|
||
{
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// convert array to IP4 array
|
||
//
|
||
|
||
parray4 = DnsAddrArray_CreateIp4Array( parray );
|
||
if ( !parray4 )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Done;
|
||
}
|
||
|
||
DNS_ASSERT( parray4->AddrCount > 0 );
|
||
|
||
Done:
|
||
|
||
DnsAddrArray_Free( parray );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
SetLastError( status );
|
||
}
|
||
return( parray4 );
|
||
}
|
||
|
||
//
|
||
// End netinfo.c
|
||
//
|