643 lines
12 KiB
C
643 lines
12 KiB
C
/*++
|
||
|
||
Copyright (c) 2000-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
config.c
|
||
|
||
Abstract:
|
||
|
||
DNS Resolver Service.
|
||
|
||
Network configuration info
|
||
|
||
Author:
|
||
|
||
Jim Gilroy (jamesg) March 2000
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "local.h"
|
||
|
||
|
||
//
|
||
// Network info
|
||
//
|
||
|
||
PDNS_NETINFO g_NetworkInfo = NULL;
|
||
DWORD g_TimeOfLastPnPUpdate;
|
||
DWORD g_NetInfoTag = 0;
|
||
DWORD g_ResetServerPriorityTime = 0;
|
||
|
||
//
|
||
// Network failure caching
|
||
//
|
||
|
||
DWORD g_NetFailureTime;
|
||
DNS_STATUS g_NetFailureStatus;
|
||
DWORD g_TimedOutAdapterTime;
|
||
BOOL g_fTimedOutAdapter;
|
||
DNS_STATUS g_PreviousNetFailureStatus;
|
||
DWORD g_MessagePopupStrikes;
|
||
DWORD g_NumberOfMessagePopups;
|
||
|
||
//
|
||
// Config globals
|
||
//
|
||
// DCR: eliminate useless config globals
|
||
//
|
||
|
||
DWORD g_HashTableSize;
|
||
DWORD g_MaxSOACacheEntryTtlLimit;
|
||
DWORD g_NegativeSOACacheTime;
|
||
DWORD g_NetFailureCacheTime;
|
||
DWORD g_MessagePopupLimit;
|
||
|
||
|
||
//
|
||
// Network Info reread time
|
||
// - currently fifteen minutes
|
||
//
|
||
|
||
#define NETWORK_INFO_REREAD_TIME (900)
|
||
|
||
|
||
|
||
|
||
//
|
||
// Network info configuration
|
||
//
|
||
|
||
VOID
|
||
UpdateNetworkInfo(
|
||
IN PDNS_NETINFO pNetInfo OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Update network info global.
|
||
|
||
Arguments:
|
||
|
||
pNetInfo -- desired network info; if NULL clear cached copy
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO poldInfo = NULL;
|
||
|
||
DNSDBG( TRACE, (
|
||
"UpdateNetworkInfo( %p )\n",
|
||
pNetInfo ));
|
||
|
||
LOCK_NET_LIST();
|
||
|
||
//
|
||
// cache previous netinfo to pickup server priority changes
|
||
// - don't cache if not same version
|
||
// - kills copy that was created before last build
|
||
// - kills copy that was before last PnP (cache clear)
|
||
// - don't cache if never reset priorities
|
||
//
|
||
|
||
if ( pNetInfo )
|
||
{
|
||
if ( pNetInfo->Tag != g_NetInfoTag )
|
||
{
|
||
DNSDBG( INIT, (
|
||
"Skip netinfo update -- previous version"
|
||
"\tptr = %p\n"
|
||
"\tversion = %d\n"
|
||
"\tcurrent version = %d\n",
|
||
pNetInfo,
|
||
pNetInfo->Tag,
|
||
g_NetInfoTag ));
|
||
poldInfo = pNetInfo;
|
||
DNS_ASSERT( pNetInfo->Tag < g_NetInfoTag );
|
||
goto Cleanup;
|
||
}
|
||
|
||
if ( g_ServerPriorityTimeLimit == 0 )
|
||
{
|
||
DNSDBG( INIT, (
|
||
"Skip netinfo update -- no priority reset!\n" ));
|
||
poldInfo = pNetInfo;
|
||
goto Cleanup;
|
||
}
|
||
|
||
NetInfo_Clean(
|
||
pNetInfo,
|
||
CLEAR_LEVEL_QUERY
|
||
);
|
||
}
|
||
|
||
//
|
||
// no netinfo means clear cached copy
|
||
// - push up tag count, so no copy out for update can
|
||
// come back and be reused through path above
|
||
|
||
else
|
||
{
|
||
g_NetInfoTag++;
|
||
}
|
||
|
||
//
|
||
// swap -- caches copy or clears
|
||
//
|
||
|
||
poldInfo = g_NetworkInfo;
|
||
g_NetworkInfo = pNetInfo;
|
||
|
||
|
||
Cleanup:
|
||
|
||
UNLOCK_NET_LIST();
|
||
|
||
NetInfo_Free( poldInfo );
|
||
}
|
||
|
||
|
||
|
||
PDNS_NETINFO
|
||
GrabNetworkInfo(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get copy of network info.
|
||
|
||
Named it "Grab" to avoid confusion with GetNetworkInfo()
|
||
in dnsapi.dll.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
Ptr to copy of network info (caller must free).
|
||
NULL on error.
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO poldInfo = NULL;
|
||
PDNS_NETINFO pnewInfo = NULL;
|
||
DWORD currentTime = Dns_GetCurrentTimeInSeconds();
|
||
|
||
DNSDBG( TRACE, ( "GrabNetworkInfo()\n" ));
|
||
|
||
//
|
||
// check for valid network info global
|
||
// - within forced reread time
|
||
// - reset server priorities if
|
||
//
|
||
|
||
LOCK_NET_LIST();
|
||
|
||
if ( g_NetworkInfo &&
|
||
g_NetworkInfo->TimeStamp + NETWORK_INFO_REREAD_TIME > currentTime )
|
||
{
|
||
if ( g_ResetServerPriorityTime < currentTime )
|
||
{
|
||
NetInfo_ResetServerPriorities( g_NetworkInfo, TRUE );
|
||
g_ResetServerPriorityTime = currentTime + g_ServerPriorityTimeLimit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// current global expired
|
||
// - build new netinfo
|
||
// - tag it with unique monotonically increasing id
|
||
// this makes sure we never use older version
|
||
// - push forward priorities reset time
|
||
// - make newinfo the global copy
|
||
//
|
||
// Do not hold lock during build
|
||
// - IpHlpApi doing routing info call RPCs to router which can
|
||
// depend on PnP notifications, which in turn can be causing calls
|
||
// back into resolver indicating config change; overall the loss
|
||
// of control is too large
|
||
//
|
||
//
|
||
// Two separate issues:
|
||
//
|
||
// There are ways to make the config change issue go away (ex setting
|
||
// some sort of "invalid" flag under interlock), but they basically boil
|
||
// down to introducing some other sort of lock.
|
||
//
|
||
// The bottom line is there are two separate issues here:
|
||
// 1) Access to cache netinfo, which may be invalidated.
|
||
// 2) Single build of netinfo for perf.
|
||
//
|
||
// Implementation wise, you can have the invalidation\clear under a
|
||
// separate interlock, and thus have a single lock for copy-access\build,
|
||
// but the reality is the same.
|
||
//
|
||
//
|
||
// Solution
|
||
// - get our tag first
|
||
// - clear lock
|
||
// - make build call
|
||
// - on return check that tag is still valid, if not we can
|
||
// USE the result, but we don't cache it, as the global tag
|
||
// could be higher because of config change, and in any case
|
||
// we let the last builder win
|
||
//
|
||
// DCR: netinfo build lock for perf, independent of protecting global
|
||
// could have "timed-lock" using event that waits for a short interval to
|
||
// to try to allow first guy to complete
|
||
//
|
||
|
||
else
|
||
{
|
||
DWORD newTag = ++g_NetInfoTag;
|
||
|
||
UNLOCK_NET_LIST();
|
||
|
||
pnewInfo = NetInfo_Build( TRUE );
|
||
if ( !pnewInfo )
|
||
{
|
||
DNSDBG( ANY, ( "ERROR: GrabNetworkInfo() failed -- no netinfo blob!\n" ));
|
||
goto Done;
|
||
}
|
||
|
||
LOCK_NET_LIST();
|
||
|
||
pnewInfo->Tag = newTag;
|
||
if ( newTag != g_NetInfoTag )
|
||
{
|
||
DNS_ASSERT( newTag < g_NetInfoTag );
|
||
DNSDBG( ANY, (
|
||
"WARNING: New netinfo uncacheable -- tag is old!\n"
|
||
"\tour tag = %d\n"
|
||
"\tcurrent tag = %d\n",
|
||
newTag,
|
||
g_NetInfoTag ));
|
||
goto Unlock;
|
||
}
|
||
|
||
// if tag still current cache this new netinfo
|
||
|
||
g_ResetServerPriorityTime = currentTime + g_ServerPriorityTimeLimit;
|
||
g_TimedOutAdapterTime = 0;
|
||
g_fTimedOutAdapter = FALSE;
|
||
|
||
poldInfo = g_NetworkInfo;
|
||
g_NetworkInfo = pnewInfo;
|
||
}
|
||
|
||
//
|
||
// make copy of global (new or reset)
|
||
//
|
||
|
||
pnewInfo = NetInfo_Copy( g_NetworkInfo );
|
||
|
||
Unlock:
|
||
|
||
UNLOCK_NET_LIST();
|
||
|
||
NetInfo_Free( poldInfo );
|
||
|
||
Done:
|
||
|
||
return pnewInfo;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ZeroNetworkConfigGlobals(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Zero init network globals.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
// net failure
|
||
|
||
g_NetFailureTime = 0;
|
||
g_NetFailureStatus = NO_ERROR;
|
||
g_PreviousNetFailureStatus = NO_ERROR;
|
||
|
||
g_fTimedOutAdapter = FALSE;
|
||
g_TimedOutAdapterTime = 0;
|
||
|
||
g_MessagePopupStrikes = 0;
|
||
g_NumberOfMessagePopups = 0;
|
||
|
||
// network info
|
||
|
||
g_TimeOfLastPnPUpdate = 0;
|
||
g_NetworkInfo = NULL;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
CleanupNetworkInfo(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cleanup network info.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
LOCK_NET_LIST();
|
||
|
||
if ( g_NetworkInfo )
|
||
{
|
||
NetInfo_Free( g_NetworkInfo );
|
||
g_NetworkInfo = NULL;
|
||
}
|
||
|
||
UNLOCK_NET_LIST();
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// General configuration
|
||
//
|
||
|
||
VOID
|
||
ReadRegistryConfig(
|
||
VOID
|
||
)
|
||
{
|
||
//
|
||
// re-read full DNS registry info
|
||
//
|
||
|
||
Reg_ReadGlobalsEx( 0, NULL );
|
||
|
||
//
|
||
// set "we are the resolver" global
|
||
//
|
||
|
||
g_InResolver = TRUE;
|
||
|
||
//
|
||
// just default old config globals until remove
|
||
//
|
||
// DCR: status of old config globals?
|
||
//
|
||
|
||
g_MaxSOACacheEntryTtlLimit = DNS_DEFAULT_MAX_SOA_TTL_LIMIT;
|
||
g_NegativeSOACacheTime = DNS_DEFAULT_NEGATIVE_SOA_CACHE_TIME;
|
||
|
||
g_NetFailureCacheTime = DNS_DEFAULT_NET_FAILURE_CACHE_TIME;
|
||
g_HashTableSize = DNS_DEFAULT_HASH_TABLE_SIZE;
|
||
g_MessagePopupLimit = DNS_DEFAULT_MESSAGE_POPUP_LIMIT;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
HandleConfigChange(
|
||
IN PSTR pszReason,
|
||
IN BOOL fCacheFlush
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Response to configuration change.
|
||
|
||
Arguments:
|
||
|
||
fCache_Flush -- flush if config change requires cache flush
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( INIT, (
|
||
"\n"
|
||
"HandleConfigChange() => %s\n"
|
||
"\tflush = %d\n",
|
||
pszReason,
|
||
fCacheFlush ));
|
||
|
||
//
|
||
// lock out all work while tear down everything
|
||
// - lock with no start option so if we are already torn
|
||
// down we don't rebuild
|
||
// - optionally flush cache
|
||
// - dump IP list
|
||
// - dump network info
|
||
//
|
||
|
||
LOCK_CACHE_NO_START();
|
||
|
||
//
|
||
// cache flush?
|
||
//
|
||
// all config changes don't necessarily require cache flush;
|
||
// if not required just rebuild local list and config
|
||
//
|
||
|
||
if ( fCacheFlush )
|
||
{
|
||
Cache_Flush();
|
||
}
|
||
else
|
||
{
|
||
ClearLocalAddrArray();
|
||
}
|
||
|
||
//
|
||
// clear network info
|
||
// save PnP time
|
||
// clear net failure flags
|
||
//
|
||
|
||
UpdateNetworkInfo( NULL );
|
||
g_TimeOfLastPnPUpdate = Dns_GetCurrentTimeInSeconds();
|
||
g_NetFailureTime = 0;
|
||
g_NetFailureStatus = NO_ERROR;
|
||
|
||
DNSDBG( INIT, (
|
||
"Leave HandleConfigChange() => %s\n"
|
||
"\tflush = %d\n\n",
|
||
pszReason,
|
||
fCacheFlush ));
|
||
|
||
UNLOCK_CACHE();
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// Remote APIs
|
||
//
|
||
|
||
VOID
|
||
R_ResolverGetConfig(
|
||
IN DNS_RPC_HANDLE Handle,
|
||
IN DWORD Cookie,
|
||
OUT PRPC_DNS_NETINFO * ppNetInfo,
|
||
OUT PDNS_GLOBALS_BLOB * ppGlobals
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Make the query to remote DNS server.
|
||
|
||
Arguments:
|
||
|
||
Handle -- RPC handle
|
||
|
||
Cookie -- cookie of last succesful config transfer
|
||
zero indicates no previous successful transfer
|
||
|
||
ppNetInfo -- addr to receive ptr to network info
|
||
|
||
ppGlobals -- addr to receive ptr to globals blob
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PDNS_GLOBALS_BLOB pblob;
|
||
|
||
DNSLOG_F1( "R_ResolverGetConfig" );
|
||
|
||
DNSDBG( RPC, (
|
||
"R_ResolverGetConfig\n"
|
||
"\tcookie = %p\n",
|
||
Cookie ));
|
||
|
||
if ( !ppNetInfo || !ppGlobals )
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// DCR: config cookie check
|
||
// - no need to get data if client has current copy
|
||
//
|
||
|
||
//
|
||
// copy network info global
|
||
//
|
||
// note: currently RPC is using same allocator (dnslib)
|
||
// as GrabNetworkInfo(); so we are ok just passing
|
||
// NETINFO blob as is
|
||
//
|
||
// note: could build on "no-global" but since we create on
|
||
// cache start we should always have global or be
|
||
// just starting
|
||
//
|
||
|
||
*ppNetInfo = (PRPC_DNS_NETINFO) GrabNetworkInfo();
|
||
|
||
pblob = (PDNS_GLOBALS_BLOB) RPC_HEAP_ALLOC( sizeof(*pblob) );
|
||
if ( pblob )
|
||
{
|
||
RtlCopyMemory(
|
||
pblob,
|
||
& DnsGlobals,
|
||
sizeof(DnsGlobals) );
|
||
|
||
// clear "in resolver" flag
|
||
|
||
pblob->InResolver = FALSE;
|
||
}
|
||
*ppGlobals = pblob;
|
||
|
||
DNSDBG( RPC, ( "Leave R_ResolverGetConfig\n\n" ));
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
R_ResolverPoke(
|
||
IN DNS_RPC_HANDLE Handle,
|
||
IN DWORD Cookie,
|
||
IN DWORD Id
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Test interface to poke resolver to update.
|
||
|
||
Arguments:
|
||
|
||
Handle -- RPC handle
|
||
|
||
Cookie -- cookie
|
||
|
||
Id -- operation Id
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNSLOG_F1( "R_ResolverPoke" );
|
||
|
||
DNSDBG( RPC, (
|
||
"R_ResolverPoke\n"
|
||
"\tcookie = %08x\n"
|
||
"\tid = %d\n",
|
||
Cookie,
|
||
Id ));
|
||
|
||
//
|
||
// do operation for particular id
|
||
// - update netinfo clears cached copy
|
||
|
||
if ( Id == POKE_OP_UPDATE_NETINFO )
|
||
{
|
||
if ( Cookie == POKE_COOKIE_UPDATE_NETINFO )
|
||
{
|
||
UpdateNetworkInfo( NULL );
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// End config.c
|
||
//
|