You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1172 lines
25 KiB
1172 lines
25 KiB
/*++
|
|
|
|
Copyright (c) 1997-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dnsrslvr.c
|
|
|
|
Abstract:
|
|
|
|
DNS Resolver Service
|
|
|
|
Main service module.
|
|
|
|
Author:
|
|
|
|
Glenn Curtis (glennc) 25-Feb-1997
|
|
|
|
Revision History:
|
|
|
|
Jim Gilroy (jamesg) March 2000 cleanup
|
|
Jim Gilroy (jamesg) Nov 2000 rewrite
|
|
|
|
--*/
|
|
|
|
|
|
#include "local.h"
|
|
|
|
#ifdef BUILD_W2K
|
|
#include <services.h>
|
|
#else
|
|
#include <svcs.h>
|
|
#endif
|
|
|
|
|
|
//
|
|
// Service control
|
|
//
|
|
|
|
SERVICE_STATUS ServiceStatus;
|
|
SERVICE_STATUS_HANDLE ServiceStatusHandle = (SERVICE_STATUS_HANDLE) 0;
|
|
|
|
PSVCHOST_GLOBAL_DATA g_pSvchostData;
|
|
|
|
|
|
HANDLE g_hStopEvent;
|
|
BOOL g_StopFlag;
|
|
|
|
BOOL g_fServiceControlHandled;
|
|
|
|
//
|
|
// Service state
|
|
//
|
|
|
|
#define RES_STATUS_BEGIN 0x0cc00000
|
|
#define RES_STATUS_ZERO_INIT 0x0cc00001
|
|
#define RES_STATUS_CREATED_CS 0x0cc00002
|
|
#define RES_STATUS_CREATED_EVENT 0x0cc00003
|
|
#define RES_STATUS_READ_REGISTRY 0x0cc00004
|
|
#define RES_STATUS_ALLOC_CACHE 0x0cc00005
|
|
#define RES_STATUS_START_NOTIFY 0x0cc00006
|
|
#define RES_STATUS_START_IP_LIST 0x0cc00007
|
|
#define RES_STATUS_START_RPC 0x0cc00008
|
|
#define RES_STATUS_REG_CONTROL 0x0cc00009
|
|
#define RES_STATUS_RUNNING 0x0cc00100
|
|
|
|
#define RES_STATUS_STOPPING 0x0cc00300
|
|
#define RES_STATUS_SIGNALED_STOP 0x0cc00301
|
|
#define RES_STATUS_STOP_RPC 0x0cc00302
|
|
#define RES_STATUS_STOP_NOTIFY 0x0cc00303
|
|
#define RES_STATUS_STOP_IP_LIST 0x0cc00304
|
|
#define RES_STATUS_FREE_CACHE 0x0cc00305
|
|
#define RES_STATUS_FREE_NET_INFO 0x0cc00306
|
|
#define RES_STATUS_FREE_IP_LIST 0x0cc00307
|
|
#define RES_STATUS_FREE_SERVICE_NOTIFY 0x0cc00308
|
|
#define RES_STATUS_DEL_EVENT 0x0cc00309
|
|
#define RES_STATUS_DEL_CS 0x0cc00310
|
|
#define RES_STATUS_END 0x0cc00400
|
|
|
|
DWORD g_ResolverStatus = RES_STATUS_BEGIN;
|
|
|
|
//
|
|
// Initialization cleanup\state
|
|
//
|
|
// Track what we intialized for safer\faster cleanup
|
|
//
|
|
|
|
#define INITFLAG_CACHE_CS 0x00000001
|
|
#define INITFLAG_NETINFO_CS 0x00000002
|
|
#define INITFLAG_NETINFO_BUILD_LOCK 0x00000004
|
|
#define INITFLAG_NETFAIL_CS 0x00000008
|
|
#define INITFLAG_WINSOCK 0x00000010
|
|
#define INITFLAG_EVENTS_CREATED 0x00000020
|
|
#define INITFLAG_CACHE_CREATED 0x00000100
|
|
#define INITFLAG_NOTIFY_STARTED 0x00001000
|
|
#define INITFLAG_IP_LIST_CREATED 0x00002000
|
|
#define INITFLAG_RPC_SERVER_STARTED 0x00010000
|
|
|
|
DWORD g_InitState;
|
|
|
|
|
|
//
|
|
// Critical sections used
|
|
//
|
|
|
|
CRITICAL_SECTION CacheCS;
|
|
CRITICAL_SECTION NetworkFailureCS;
|
|
|
|
|
|
//
|
|
// Logging control
|
|
//
|
|
|
|
BOOL g_LogTraceInfo = TRUE;
|
|
|
|
|
|
//
|
|
// Private protos
|
|
//
|
|
|
|
DWORD
|
|
ResolverInitialize(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
ResolverShutdown(
|
|
IN DWORD ErrorCode
|
|
);
|
|
|
|
VOID
|
|
ResolverControlHandler(
|
|
IN DWORD Opcode
|
|
);
|
|
|
|
DWORD
|
|
ResolverUpdateStatus(
|
|
VOID
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// Service routines
|
|
//
|
|
|
|
VOID
|
|
SvchostPushServiceGlobals(
|
|
PSVCHOST_GLOBAL_DATA pGlobals
|
|
)
|
|
{
|
|
g_pSvchostData = pGlobals;
|
|
}
|
|
|
|
|
|
VOID
|
|
ServiceMain(
|
|
IN DWORD NumArgs,
|
|
IN LPTSTR * ArgsArray
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Main entry point of resolver service.
|
|
|
|
Arguments:
|
|
|
|
NumArgs - number of strings specified in ArgsArray.
|
|
|
|
ArgsArray - array of ptrs to arguments in service start call
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Make sure svchost.exe gave us global data
|
|
//
|
|
|
|
ASSERT( g_pSvchostData != NULL );
|
|
|
|
//
|
|
// Startup service, then exit
|
|
//
|
|
|
|
ResolverInitialize();
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ResolverInitFailure(
|
|
IN DNS_STATUS Status,
|
|
IN DWORD EventId,
|
|
IN DWORD MemEventId,
|
|
IN PSTR pszDebugString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle resolver init failure.
|
|
|
|
Function exists to avoid duplicate code.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
WCHAR numberString[16];
|
|
PWSTR eventStrings[1];
|
|
|
|
DNSLOG_TIME();
|
|
DNSLOG_F1( "Resolver Init Failure" );
|
|
DNSLOG_F2( " Failure = %s", pszDebugString );
|
|
DNSLOG_F2( " Status = %d", Status );
|
|
DNSLOG_F1( "" );
|
|
|
|
DNSDBG( ANY, (
|
|
"Resolver Init FAILED!\n"
|
|
"\tname = %s\n"
|
|
"\tstatus = %d\n"
|
|
"\tevent id = %d\n"
|
|
"\tmem event = %08x\n",
|
|
pszDebugString,
|
|
Status,
|
|
EventId,
|
|
MemEventId ));
|
|
|
|
DnsDbg_PrintfToDebugger(
|
|
"ResolverInitialize - Returning status %d 0x%08x\n"
|
|
"\tname = %s\n",
|
|
Status, Status,
|
|
pszDebugString );
|
|
|
|
//
|
|
// log in memory event
|
|
//
|
|
|
|
LogEventInMemory( MemEventId, Status );
|
|
|
|
//
|
|
// log event
|
|
// - convert status to string
|
|
//
|
|
|
|
wsprintfW( numberString, L"0x%.8X", Status );
|
|
eventStrings[0] = numberString;
|
|
|
|
ResolverLogEvent(
|
|
EventId,
|
|
EVENTLOG_ERROR_TYPE,
|
|
1,
|
|
eventStrings,
|
|
Status );
|
|
|
|
// clean up
|
|
|
|
ResolverShutdown( Status );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ResolverInitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the DNS Caching Resolver service.
|
|
|
|
Arguments:
|
|
|
|
InitState - Returns a flag to indicate how far we got with
|
|
initializing the service before an error occurred.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ErrorCode on failure.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
|
|
//
|
|
// init service state
|
|
//
|
|
|
|
g_ResolverStatus = RES_STATUS_BEGIN;
|
|
g_InitState = 0;
|
|
g_StopFlag = FALSE;
|
|
g_hStopEvent = NULL;
|
|
g_fServiceControlHandled = FALSE;
|
|
|
|
//
|
|
// initialize logging
|
|
//
|
|
|
|
DNSLOG_INIT();
|
|
DNSLOG_F1( "DNS Caching Resolver Service - ResolverInitialize" );
|
|
|
|
#if DBG
|
|
Dns_StartDebugEx(
|
|
0, // no flag value
|
|
"dnsres.flag",
|
|
NULL, // no external flag
|
|
"dnsres.log",
|
|
0, // no wrap limit
|
|
FALSE, // don't use existing global
|
|
FALSE,
|
|
TRUE // make this file global
|
|
);
|
|
#endif
|
|
|
|
DNSDBG( INIT, ( "DNS resolver startup.\n" ));
|
|
IF_DNSDBG( START_BREAK )
|
|
{
|
|
// since resolver moved to NetworkServices permissions do
|
|
// not properly bring up ntsd; instead just give time
|
|
// to attach debugger
|
|
|
|
Sleep( 20000 );
|
|
}
|
|
|
|
//
|
|
// initialize service status block
|
|
//
|
|
|
|
ServiceStatusHandle = (SERVICE_STATUS_HANDLE) 0;
|
|
|
|
ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
|
|
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
|
ServiceStatus.dwControlsAccepted = 0;
|
|
ServiceStatus.dwCheckPoint = 0;
|
|
ServiceStatus.dwWaitHint = 5000;
|
|
ServiceStatus.dwWin32ExitCode = NO_ERROR;
|
|
ServiceStatus.dwServiceSpecificExitCode = 0;
|
|
|
|
ResolverUpdateStatus();
|
|
|
|
//
|
|
// init globals to zero
|
|
//
|
|
|
|
ZeroInitIpListGlobals();
|
|
ZeroNetworkConfigGlobals();
|
|
g_ResolverStatus = RES_STATUS_ZERO_INIT;
|
|
|
|
//
|
|
// initialize all our critical sections as soon as we can
|
|
//
|
|
|
|
LogEventInMemory( RES_EVENT_INITCRIT_START, 0 );
|
|
|
|
if ( RtlInitializeCriticalSection( &CacheCS ) != NO_ERROR )
|
|
{
|
|
goto Failed;
|
|
}
|
|
g_InitState |= INITFLAG_CACHE_CS;
|
|
if ( RtlInitializeCriticalSection( &NetworkFailureCS ) != NO_ERROR )
|
|
{
|
|
goto Failed;
|
|
}
|
|
g_InitState |= INITFLAG_NETFAIL_CS;
|
|
if ( RtlInitializeCriticalSection( &NetinfoCS ) != NO_ERROR )
|
|
{
|
|
goto Failed;
|
|
}
|
|
g_InitState |= INITFLAG_NETINFO_CS;
|
|
if ( TimedLock_Initialize( &NetinfoBuildLock, 5000 ) != NO_ERROR )
|
|
{
|
|
goto Failed;
|
|
}
|
|
g_InitState |= INITFLAG_NETINFO_BUILD_LOCK;
|
|
|
|
LogEventInMemory( RES_EVENT_INITCRIT_END,0 );
|
|
|
|
//
|
|
// init our dnslib heap to use dnsapi heap
|
|
//
|
|
// this is important because we currently mix and match records
|
|
// created inside dnsapi (hosts file and query) with a few that
|
|
// we roll on our own; need this to be common
|
|
//
|
|
|
|
Dns_LibHeapReset( DnsApiAlloc, DnsApiRealloc, DnsApiFree );
|
|
|
|
//
|
|
// init winsock
|
|
//
|
|
|
|
Socket_InitWinsock();
|
|
g_InitState |= INITFLAG_WINSOCK;
|
|
|
|
//
|
|
// shutdown event
|
|
//
|
|
|
|
g_hStopEvent = CreateEvent(
|
|
NULL, // no security descriptor
|
|
TRUE, // do not use automatic reset
|
|
FALSE, // initial state: not signalled
|
|
NULL // no name
|
|
);
|
|
if ( !g_hStopEvent )
|
|
{
|
|
status = GetLastError();
|
|
|
|
ResolverInitFailure(
|
|
status,
|
|
0,
|
|
0,
|
|
"CreateEvent() failed" );
|
|
return status;
|
|
}
|
|
g_InitState |= INITFLAG_EVENTS_CREATED;
|
|
g_ResolverStatus = RES_STATUS_CREATED_EVENT;
|
|
|
|
ResolverUpdateStatus();
|
|
|
|
//
|
|
// initialize our global registry values
|
|
// - force this just once on startup so we have the
|
|
// relevant cache params; after that read only on
|
|
// demand when building netinfo blobs
|
|
|
|
ReadRegistryConfig();
|
|
|
|
//
|
|
// Set the query timeouts to be used from defaults or registry
|
|
//
|
|
|
|
Dns_InitQueryTimeouts();
|
|
|
|
//
|
|
// init socket caching
|
|
// - improves perf and prevents socket DOS attack
|
|
// - default cache to 10 sockets
|
|
//
|
|
// DCR: create global for socket caching
|
|
//
|
|
|
|
Socket_CacheInit( 10 );
|
|
|
|
//
|
|
// notification thread (host file and registry)
|
|
//
|
|
|
|
StartNotify();
|
|
g_InitState |= INITFLAG_NOTIFY_STARTED;
|
|
g_ResolverStatus = RES_STATUS_START_NOTIFY;
|
|
ResolverUpdateStatus();
|
|
|
|
//
|
|
// IP notification thread
|
|
//
|
|
|
|
status = InitIpListAndNotification();
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
ResolverInitFailure(
|
|
status,
|
|
0,
|
|
0,
|
|
"IP list init failed" );
|
|
return status;
|
|
}
|
|
g_InitState |= INITFLAG_IP_LIST_CREATED;
|
|
g_ResolverStatus = RES_STATUS_START_IP_LIST;
|
|
ResolverUpdateStatus();
|
|
|
|
//
|
|
// register control handler
|
|
// allows us to receive service requests
|
|
//
|
|
|
|
ServiceStatusHandle = RegisterServiceCtrlHandlerW(
|
|
DNS_RESOLVER_SERVICE,
|
|
ResolverControlHandler
|
|
);
|
|
if ( !ServiceStatusHandle )
|
|
{
|
|
status = GetLastError();
|
|
ResolverInitFailure(
|
|
status,
|
|
EVENT_DNS_CACHE_START_FAILURE_LOW_MEMORY,
|
|
RES_EVENT_REGISTER_SCH,
|
|
"Call to RegisterServiceCtrlHandlerW failed!"
|
|
);
|
|
return status;
|
|
}
|
|
g_ResolverStatus = RES_STATUS_REG_CONTROL;
|
|
ResolverUpdateStatus();
|
|
|
|
//
|
|
// initialize RPC interfaces
|
|
// - bump our requested stack size up to 8K
|
|
// (RPC uses 1800 bytes before we get the stack,
|
|
// the new() operator followed by the heap code uses
|
|
// another 1200 -- leaving only about a 1000 for
|
|
// DNS)
|
|
//
|
|
|
|
LogEventInMemory( RES_EVENT_START_RPC, 0 );
|
|
|
|
#if 0
|
|
// should not be necessary
|
|
// default for all svchost instances has been increased
|
|
if ( status != NO_ERROR )
|
|
{
|
|
DNSDBG( ANY, (
|
|
"RpcMgmtSetServerStackSize( 2000 ) = %d\n",
|
|
status ));
|
|
}
|
|
#endif
|
|
|
|
status = Rpc_Initialize();
|
|
#if 0
|
|
status = g_pSvchostData->StartRpcServer(
|
|
SERVER_INTERFACE_NAME_W,
|
|
DnsResolver_ServerIfHandle );
|
|
#endif
|
|
if ( status != NO_ERROR )
|
|
{
|
|
LogEventInMemory( RES_EVENT_STATUS, status );
|
|
|
|
if ( status == RPC_S_TYPE_ALREADY_REGISTERED ||
|
|
status == RPC_NT_TYPE_ALREADY_REGISTERED )
|
|
{
|
|
DNSLOG_TIME();
|
|
DNSLOG_F1( " Call to StartRpcServer returned warning that" );
|
|
DNSLOG_F1( " the service is already running!" );
|
|
DNSLOG_F2( " RpcPipeName : %S", RESOLVER_INTERFACE_NAME_W );
|
|
DNSLOG_F1( " Going to just continue running . . ." );
|
|
DNSLOG_F1( "" );
|
|
|
|
DnsDbg_PrintfToDebugger(
|
|
"DNS Client (dnsrslvr.dll) - Call to StartRpcServer\n"
|
|
"returned warning that the service is already running!\n"
|
|
"RpcPipeName : %S"
|
|
"Going to just continue running . . .\n",
|
|
RESOLVER_INTERFACE_NAME_W );
|
|
|
|
status = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
DNSDBG( ANY, (
|
|
"RPC init FAILED! status = %d\n"
|
|
"\tpipe name = %s\n",
|
|
status,
|
|
RESOLVER_INTERFACE_NAME_W ));
|
|
|
|
ResolverInitFailure(
|
|
status,
|
|
EVENT_DNS_CACHE_START_FAILURE_NO_RPC,
|
|
0,
|
|
"Call to StartRpcServer failed!"
|
|
);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
g_ResolverStatus = RES_STATUS_START_RPC;
|
|
g_InitState |= INITFLAG_RPC_SERVER_STARTED;
|
|
|
|
//
|
|
// successful startup
|
|
// - indicate running
|
|
// - indicate what service control messages we want to get
|
|
//
|
|
|
|
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
|
|
SERVICE_ACCEPT_PARAMCHANGE |
|
|
SERVICE_ACCEPT_NETBINDCHANGE;
|
|
ServiceStatus.dwWaitHint = 0;
|
|
ServiceStatus.dwWin32ExitCode = NO_ERROR;
|
|
|
|
ResolverUpdateStatus();
|
|
|
|
g_ResolverStatus = RES_STATUS_RUNNING;
|
|
LogEventInMemory( RES_EVENT_STARTED, 0 );
|
|
|
|
DNSLOG_F1( "ResolverInitialize - Successful" );
|
|
DNSLOG_F1( "" );
|
|
return NO_ERROR;
|
|
|
|
Failed:
|
|
|
|
if ( status == NO_ERROR )
|
|
{
|
|
status = DNS_ERROR_NO_MEMORY;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ResolverShutdown(
|
|
IN DWORD ErrorCode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function shuts down the DNS cache service.
|
|
|
|
Arguments:
|
|
|
|
ErrorCode - Supplies the error code of the failure
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
LONG existingStopFlag;
|
|
|
|
DNSLOG_TIME();
|
|
DNSLOG_F1( "DNS Caching Resolver Service - ResolverShutdown" );
|
|
DnsDbg_PrintfToDebugger( "DNS Client - ResolverShutdown!\n" );
|
|
|
|
//
|
|
// indicate shutdown
|
|
// - but interlock to avoid dual shutdown
|
|
//
|
|
|
|
existingStopFlag = InterlockedExchange(
|
|
&g_StopFlag,
|
|
(LONG) TRUE );
|
|
if ( existingStopFlag )
|
|
{
|
|
DNS_ASSERT( FALSE );
|
|
return;
|
|
}
|
|
DNS_ASSERT( g_StopFlag );
|
|
|
|
//
|
|
// indicate stop in progress
|
|
//
|
|
|
|
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|
ServiceStatus.dwCheckPoint = 1;
|
|
ServiceStatus.dwWaitHint = 60000;
|
|
ResolverUpdateStatus();
|
|
|
|
g_ResolverStatus = RES_STATUS_STOPPING;
|
|
|
|
|
|
//
|
|
// wakeup threads to shut down
|
|
//
|
|
|
|
LogEventInMemory( RES_EVENT_STOPPING, 0 );
|
|
|
|
g_StopFlag = TRUE;
|
|
if ( g_hStopEvent )
|
|
{
|
|
if ( !SetEvent(g_hStopEvent) )
|
|
{
|
|
DnsDbg_PrintfToDebugger(
|
|
"DNSCACHE: Error setting g_hStopEvent %lu\n",
|
|
GetLastError());
|
|
DNS_ASSERT( FALSE );
|
|
}
|
|
}
|
|
g_ResolverStatus = RES_STATUS_SIGNALED_STOP;
|
|
|
|
//
|
|
// cleanup RPC
|
|
//
|
|
|
|
if ( g_InitState & INITFLAG_RPC_SERVER_STARTED )
|
|
{
|
|
LogEventInMemory( RES_EVENT_STOP_RPC, 0 );
|
|
|
|
Rpc_Shutdown();
|
|
#if 0
|
|
//status = g_pSvchostData->StopRpcServer( DnsResolver_ServerIfHandle );
|
|
#endif
|
|
}
|
|
g_ResolverStatus = RES_STATUS_STOP_RPC;
|
|
|
|
//
|
|
// re-signal stop within lock
|
|
//
|
|
|
|
LOCK_CACHE_NO_START();
|
|
g_StopFlag = TRUE;
|
|
if ( g_hStopEvent )
|
|
{
|
|
if ( !SetEvent(g_hStopEvent) )
|
|
{
|
|
DnsDbg_PrintfToDebugger(
|
|
"DNSCACHE: Error setting g_hStopEvent %lu\n",
|
|
GetLastError());
|
|
DNS_ASSERT( FALSE );
|
|
}
|
|
}
|
|
UNLOCK_CACHE();
|
|
|
|
//
|
|
// stop notify thread
|
|
//
|
|
|
|
if ( g_InitState & INITFLAG_NOTIFY_STARTED )
|
|
{
|
|
ShutdownNotify();
|
|
}
|
|
g_ResolverStatus = RES_STATUS_STOP_NOTIFY;
|
|
|
|
//
|
|
// stop IP notify thread
|
|
//
|
|
|
|
if ( g_InitState & INITFLAG_IP_LIST_CREATED )
|
|
{
|
|
ShutdownIpListAndNotify();
|
|
}
|
|
g_ResolverStatus = RES_STATUS_STOP_IP_LIST;
|
|
|
|
//
|
|
// cleanup cache
|
|
//
|
|
|
|
Cache_Shutdown();
|
|
g_ResolverStatus = RES_STATUS_FREE_CACHE;
|
|
|
|
//
|
|
// cleanup service notification list
|
|
//
|
|
|
|
//CleanupServiceNotification();
|
|
//g_ResolverStatus = RES_STATUS_FREE_SERVICE_NOTIFY;
|
|
|
|
//
|
|
// cleanup network info globals
|
|
//
|
|
|
|
CleanupNetworkInfo();
|
|
g_ResolverStatus = RES_STATUS_FREE_NET_INFO;
|
|
|
|
//
|
|
// cleanup winsock
|
|
// cleanup socket caching also
|
|
// - this is irrelevant for other services running in
|
|
// our process so we shouldn't leave the handles open
|
|
//
|
|
|
|
if ( g_InitState & INITFLAG_WINSOCK )
|
|
{
|
|
Socket_CacheCleanup();
|
|
Socket_CleanupWinsock();
|
|
}
|
|
|
|
//
|
|
// cleanup main shutdown event
|
|
//
|
|
|
|
if ( g_InitState & INITFLAG_EVENTS_CREATED )
|
|
{
|
|
if ( g_hStopEvent )
|
|
{
|
|
CloseHandle(g_hStopEvent);
|
|
g_hStopEvent = NULL;
|
|
}
|
|
}
|
|
g_ResolverStatus = RES_STATUS_DEL_EVENT;
|
|
|
|
//
|
|
// delete critical sections\locks
|
|
//
|
|
|
|
if ( g_InitState & INITFLAG_CACHE_CS )
|
|
{
|
|
DeleteCriticalSection( &CacheCS );
|
|
}
|
|
if ( g_InitState & INITFLAG_NETFAIL_CS )
|
|
{
|
|
DeleteCriticalSection( &NetworkFailureCS );
|
|
}
|
|
if ( g_InitState & INITFLAG_NETINFO_CS )
|
|
{
|
|
DeleteCriticalSection( &NetinfoCS );
|
|
}
|
|
if ( g_InitState & INITFLAG_NETINFO_BUILD_LOCK )
|
|
{
|
|
TimedLock_Cleanup( &NetinfoBuildLock );
|
|
}
|
|
g_ResolverStatus = RES_STATUS_DEL_CS;
|
|
|
|
//
|
|
// cleanup complete
|
|
// tell Service Controller that we are stopped
|
|
//
|
|
|
|
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
|
ServiceStatus.dwControlsAccepted = 0;
|
|
ServiceStatus.dwWin32ExitCode = ErrorCode;
|
|
ServiceStatus.dwServiceSpecificExitCode = 0;
|
|
ServiceStatus.dwCheckPoint = 0;
|
|
ServiceStatus.dwWaitHint = 0;
|
|
|
|
ResolverUpdateStatus();
|
|
|
|
g_ResolverStatus = RES_STATUS_END;
|
|
|
|
DNSLOG_F1( "ResolverShutdown - Finished" );
|
|
DNSLOG_F1( "" );
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
GetServiceControlLock(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get exclusive access handling service control message.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE -- have exclusive access to handle SCM, other threads locked out
|
|
FALSE -- another thread still handling SCM
|
|
|
|
--*/
|
|
{
|
|
BOOL fresult;
|
|
|
|
//
|
|
// set handled flag, if not previously set
|
|
// if not previous set -> we have exclusive access
|
|
//
|
|
|
|
fresult = InterlockedCompareExchange(
|
|
&g_fServiceControlHandled,
|
|
(LONG) TRUE, // new value
|
|
(LONG) 0 // previous value to do exchange
|
|
);
|
|
|
|
return !fresult;
|
|
}
|
|
|
|
|
|
VOID
|
|
ReleaseServiceControlLock(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Release service control exclusive access.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// clear handled flag
|
|
// - since GetServiceControlLock() uses CompareExchange
|
|
// we can just clear without interlock
|
|
//
|
|
|
|
DNS_ASSERT( g_fServiceControlHandled );
|
|
g_fServiceControlHandled = FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
ResolverControlHandler(
|
|
IN DWORD Opcode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Service control handler for DNS cache service.
|
|
|
|
Arguments:
|
|
|
|
Opcode - specifies service action
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
LogEventInMemory( RES_EVENT_SERVICE_CONTROL, Opcode );
|
|
|
|
DNSLOG_TIME();
|
|
DNSLOG_F2( "ResolverControlHandler - Recieved opcode %d", Opcode );
|
|
|
|
DNSDBG( ANY, (
|
|
"\n\n"
|
|
"ResolverControlHandler() Opcode = %d\n",
|
|
Opcode ));
|
|
|
|
//
|
|
// handle various service control codes
|
|
//
|
|
|
|
switch( Opcode )
|
|
{
|
|
|
|
case SERVICE_CONTROL_STOP:
|
|
|
|
//
|
|
// shutdown
|
|
// - ResolverShutdown() updates status with SCM, so we don't update
|
|
// status here (as SCM will start invalidating stuff on stop)
|
|
// but jump directly to exit
|
|
//
|
|
|
|
ResolverShutdown( NO_ERROR );
|
|
goto Done;
|
|
|
|
case SERVICE_CONTROL_PARAMCHANGE :
|
|
|
|
DNSLOG_F1( " Handle Paramchange" );
|
|
DNSLOG_F1( "" );
|
|
|
|
if ( !GetServiceControlLock() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// rebuild -- with cache flush
|
|
//
|
|
|
|
HandleConfigChange(
|
|
"SC -- ParamChange",
|
|
TRUE // flush cache
|
|
);
|
|
|
|
//
|
|
// signal other services about PnP
|
|
//
|
|
// SendServiceNotifications();
|
|
|
|
ReleaseServiceControlLock();
|
|
break;
|
|
|
|
case SERVICE_CONTROL_NETBINDENABLE:
|
|
case SERVICE_CONTROL_NETBINDDISABLE:
|
|
|
|
DNSLOG_F1( " Handle NetBindEnable\\Disable" );
|
|
DNSLOG_F1( "" );
|
|
|
|
if ( !GetServiceControlLock() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// rebuild -- with cache flush
|
|
//
|
|
|
|
HandleConfigChange(
|
|
"SC -- NetBind",
|
|
TRUE // flush cache
|
|
);
|
|
|
|
ReleaseServiceControlLock();
|
|
break;
|
|
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
case SERVICE_CONTROL_NETBINDADD:
|
|
case SERVICE_CONTROL_NETBINDREMOVE:
|
|
default:
|
|
|
|
DNSLOG_F1( " This is an unknown opcode, ignoring ..." );
|
|
DNSLOG_F1( "" );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// update service status
|
|
//
|
|
|
|
ResolverUpdateStatus();
|
|
|
|
Done:
|
|
|
|
DNSLOG_F2( "Resolver Controll Handler (opcode = %d) -- returning", Opcode );
|
|
|
|
DNSDBG( ANY, (
|
|
"Leaving ResolverControlHandler( %d )\n\n\n",
|
|
Opcode ));
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ResolverUpdateStatus(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update service controller with current service status.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Return code from SetServiceStatus.
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
DWORD logStatus;
|
|
|
|
DNSDBG( TRACE, ( "ResolverUpdateStatus()\n" ));
|
|
|
|
//
|
|
// bump the checkpoint
|
|
//
|
|
|
|
ServiceStatus.dwCheckPoint++;
|
|
|
|
if ( ServiceStatusHandle == (SERVICE_STATUS_HANDLE) 0 )
|
|
{
|
|
LogEventInMemory( RES_EVENT_UPDATE_STATUS, ERROR_INVALID_HANDLE );
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
//
|
|
// log memory event
|
|
// - the current state
|
|
// - the error, if exists
|
|
|
|
LogEventInMemory( RES_EVENT_UPDATE_STATE, ServiceStatus.dwCurrentState );
|
|
|
|
status = ServiceStatus.dwWin32ExitCode;
|
|
if ( status != NO_ERROR )
|
|
{
|
|
LogEventInMemory( RES_EVENT_UPDATE_STATUS, status );
|
|
}
|
|
|
|
//
|
|
// update service controller
|
|
//
|
|
|
|
if ( ! SetServiceStatus( ServiceStatusHandle, &ServiceStatus ) )
|
|
{
|
|
status = GetLastError();
|
|
LogEventInMemory( RES_EVENT_UPDATE_STATUS, status );
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Event logging
|
|
//
|
|
|
|
VOID
|
|
ResolverLogEvent(
|
|
IN DWORD MessageId,
|
|
IN WORD EventType,
|
|
IN DWORD StringCount,
|
|
IN PWSTR * StringArray,
|
|
IN DWORD ErrorCode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Log to eventlog.
|
|
|
|
Arguments:
|
|
|
|
MessageId -- event message id
|
|
|
|
EventType -- event type (error, warning, info, etc.)
|
|
|
|
StringCount -- string arg count
|
|
|
|
StringArray -- imbedded strings
|
|
|
|
ErrorCode -- error code for data section of event
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
HANDLE hlog;
|
|
PVOID pdata = NULL;
|
|
|
|
//
|
|
// open resolver as event source
|
|
//
|
|
// note: we don't keep log open because events are few
|
|
//
|
|
|
|
hlog = RegisterEventSourceW(
|
|
NULL,
|
|
DNS_RESOLVER_SERVICE );
|
|
|
|
if ( hlog == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( ErrorCode != NO_ERROR )
|
|
{
|
|
pdata = &ErrorCode;
|
|
}
|
|
|
|
//
|
|
// Write to event log
|
|
//
|
|
// DCR: should get suppression technology here
|
|
//
|
|
|
|
ReportEventW(
|
|
hlog,
|
|
EventType,
|
|
0, // event category
|
|
MessageId,
|
|
(PSID) NULL,
|
|
(WORD) StringCount,
|
|
sizeof(DWORD),
|
|
StringArray,
|
|
(PVOID) pdata );
|
|
|
|
DeregisterEventSource( hlog );
|
|
}
|
|
|
|
|
|
//
|
|
// End dnsrslvr.c
|
|
//
|