1209 lines
24 KiB
C
1209 lines
24 KiB
C
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
#ifdef BUILD_W2K
|
|||
|
PSVCS_GLOBAL_DATA g_pSvchostData;
|
|||
|
#else
|
|||
|
PSVCHOST_GLOBAL_DATA g_pSvchostData;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
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_CS_CREATED 0x00000001
|
|||
|
#define INITFLAG_WINSOCK 0x00000002
|
|||
|
#define INITFLAG_EVENTS_CREATED 0x00000004
|
|||
|
#define INITFLAG_CACHE_CREATED 0x00000008
|
|||
|
#define INITFLAG_NOTIFY_STARTED 0x00000010
|
|||
|
#define INITFLAG_IP_LIST_CREATED 0x00000020
|
|||
|
#define INITFLAG_RPC_SERVER_STARTED 0x00000100
|
|||
|
|
|||
|
DWORD g_InitState;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Critical sections used
|
|||
|
//
|
|||
|
|
|||
|
CRITICAL_SECTION CacheCritSec;
|
|||
|
CRITICAL_SECTION NetworkListCritSec;
|
|||
|
CRITICAL_SECTION NetworkFailureCritSec;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// 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
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// NT5 version -- inside services.exe
|
|||
|
//
|
|||
|
|
|||
|
#ifdef BUILD_W2K
|
|||
|
|
|||
|
VOID
|
|||
|
SVCS_ENTRY_POINT(
|
|||
|
DWORD NumArgs,
|
|||
|
LPTSTR * ArgsArray,
|
|||
|
PSVCS_GLOBAL_DATA pSvcsGlobalData,
|
|||
|
HANDLE SvcRefHandle
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Main main entry point of resolver service
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NumArgs - number of arguments to service start call
|
|||
|
|
|||
|
ArgsArray - array of ptrs to arguments in service start call
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
//
|
|||
|
// save pointer to service data block
|
|||
|
//
|
|||
|
|
|||
|
g_pSvchostData = pSvcsGlobalData;
|
|||
|
|
|||
|
ResolverInitialize();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#else
|
|||
|
//
|
|||
|
// Whistler+ version -- in svchost.exe process
|
|||
|
//
|
|||
|
|
|||
|
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();
|
|||
|
}
|
|||
|
|
|||
|
#endif // NT4 \ Whistler+ switch
|
|||
|
|
|||
|
|
|||
|
|
|||
|
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
|
|||
|
#if 0
|
|||
|
Dns_StartDebug(
|
|||
|
0,
|
|||
|
"dnsres.flag",
|
|||
|
NULL,
|
|||
|
"dnsres.log",
|
|||
|
0 );
|
|||
|
#endif
|
|||
|
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 );
|
|||
|
InitializeCriticalSection( & CacheCritSec );
|
|||
|
InitializeCriticalSection( & NetworkListCritSec );
|
|||
|
InitializeCriticalSection( & NetworkFailureCritSec );
|
|||
|
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
|
|||
|
//
|
|||
|
|
|||
|
Dns_InitializeWinsock();
|
|||
|
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
|
|||
|
//
|
|||
|
|
|||
|
Dns_CacheSocketInit( 10 );
|
|||
|
|
|||
|
#if 0
|
|||
|
//
|
|||
|
// start cache on demand now
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// initialize cache
|
|||
|
//
|
|||
|
|
|||
|
status = Cache_Initialize();
|
|||
|
|
|||
|
LogEventInMemory( RES_EVENT_INITCACHE, status );
|
|||
|
|
|||
|
if ( status != NO_ERROR )
|
|||
|
{
|
|||
|
ResolverInitFailure(
|
|||
|
status,
|
|||
|
EVENT_DNS_CACHE_START_FAILURE_NO_CONTROL,
|
|||
|
0,
|
|||
|
"Cache_Initialize() failed" );
|
|||
|
return status;
|
|||
|
}
|
|||
|
g_InitState |= INITFLAG_CACHE_CREATED;
|
|||
|
g_ResolverStatus = RES_STATUS_ALLOC_CACHE;
|
|||
|
ResolverUpdateStatus();
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// 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_STARTRPC, 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;
|
|||
|
|
|||
|
DNSLOG_F1( "ResolverInitialize - Successful" );
|
|||
|
DNSLOG_F1( "" );
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
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
|
|||
|
//
|
|||
|
|
|||
|
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_STOPRPC, 0 );
|
|||
|
|
|||
|
Rpc_Shutdown();
|
|||
|
#if 0
|
|||
|
//status = g_pSvchostData->StopRpcServer( DnsResolver_ServerIfHandle );
|
|||
|
#endif
|
|||
|
LogEventInMemory( RES_EVENT_STATUS, status );
|
|||
|
}
|
|||
|
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 )
|
|||
|
{
|
|||
|
Dns_CacheSocketCleanup();
|
|||
|
Dns_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
|
|||
|
//
|
|||
|
|
|||
|
if ( g_InitState & INITFLAG_CS_CREATED )
|
|||
|
{
|
|||
|
LogEventInMemory( RES_EVENT_DELCRIT_START, 0 );
|
|||
|
DeleteCriticalSection( &CacheCritSec );
|
|||
|
DeleteCriticalSection( &NetworkListCritSec );
|
|||
|
DeleteCriticalSection( &NetworkFailureCritSec );
|
|||
|
LogEventInMemory( RES_EVENT_DELCRIT_END, 0 );
|
|||
|
}
|
|||
|
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_SCH, 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:
|
|||
|
|
|||
|
ResolverShutdown( NO_ERROR );
|
|||
|
break;
|
|||
|
|
|||
|
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();
|
|||
|
|
|||
|
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 = NO_ERROR;
|
|||
|
|
|||
|
DNSDBG( TRACE, ( "ResolverUpdateStatus()\n" ));
|
|||
|
|
|||
|
//
|
|||
|
// bump the checkpoint
|
|||
|
// if status, set it
|
|||
|
|
|||
|
ServiceStatus.dwCheckPoint++;
|
|||
|
#if 0
|
|||
|
if ( Status )
|
|||
|
{
|
|||
|
ServiceStatus.dwWin32ExitCode = Status;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// DCR_FIX: this doesn't do much
|
|||
|
// usually people write something like this that sets the service
|
|||
|
// state AND does the update
|
|||
|
//
|
|||
|
// QUESTION: what's up with the LogEventInMemory?
|
|||
|
//
|
|||
|
|
|||
|
if ( ServiceStatusHandle == (SERVICE_STATUS_HANDLE) 0 )
|
|||
|
{
|
|||
|
LogEventInMemory( RES_EVENT_UPDATE_STATUS, ERROR_INVALID_HANDLE );
|
|||
|
return ERROR_INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
LogEventInMemory( RES_EVENT_UPDATE_STATUS, ServiceStatus.dwWin32ExitCode );
|
|||
|
|
|||
|
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
|
|||
|
//
|