[DNSRSLVR] Add the DNS Resolver Cache Service

Patch written by Peter Hater and Christoph von Wittich.

Slightly modified by me in order to
- fix bit-rot
- fix header include issues
- disable integration with dnsapi because of confusing use of DnsQweryEx().

Integration with dnsapi will follow in a future commit.

CORE-12159
This commit is contained in:
Eric Kohl 2019-10-27 13:45:52 +01:00
parent 6889cff5b5
commit d49d7b3282
11 changed files with 578 additions and 1 deletions

View file

@ -2,6 +2,7 @@
add_subdirectory(audiosrv)
add_subdirectory(dcomlaunch)
add_subdirectory(dhcpcsvc)
add_subdirectory(dnsrslvr)
add_subdirectory(eventlog)
add_subdirectory(netlogon)
add_subdirectory(nfsd)

View file

@ -0,0 +1,23 @@
include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl)
add_rpc_files(server ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl/dnsrslvr.idl)
list(APPEND SOURCE
cache.c
dnsrslvr.c
rpcserver.c
precomp.h
${CMAKE_CURRENT_BINARY_DIR}/dnsrslvr_s.c)
spec2def(dnsrslvr.dll dnsrslvr.spec ADD_IMPORTLIB)
add_library(dnsrslvr SHARED ${SOURCE} dnsrslvr.rc ${CMAKE_CURRENT_BINARY_DIR}/dnsrslvr.def)
if(NOT MSVC)
target_link_libraries(dnsrslvr ${PSEH_LIB})
endif()
set_module_type(dnsrslvr win32dll UNICODE)
add_importlibs(dnsrslvr advapi32 rpcrt4 dnsapi iphlpapi msvcrt kernel32 ntdll)
add_pch(dnsrslvr precomp.h SOURCE)
add_cd_file(TARGET dnsrslvr DESTINATION reactos/system32 FOR all)

View file

@ -0,0 +1,199 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: base/services/dnsrslvr/cache.c
* PURPOSE: DNS cache functions
* PROGRAMMER: Peter Hater
*/
#include "precomp.h"
//#define NDEBUG
#include <debug.h>
static RESOLVER_CACHE DnsCache;
static BOOL DnsCacheInitialized = FALSE;
#define DnsCacheLock() do { EnterCriticalSection(&DnsCache.Lock); } while (0)
#define DnsCacheUnlock() do { LeaveCriticalSection(&DnsCache.Lock); } while (0)
VOID
DnsIntCacheInitialize(VOID)
{
DPRINT("DnsIntCacheInitialize\n");
/* Check if we're initialized */
if (DnsCacheInitialized)
return;
/* Initialize the cache lock and namespace list */
InitializeCriticalSection((LPCRITICAL_SECTION)&DnsCache.Lock);
InitializeListHead(&DnsCache.RecordList);
DnsCacheInitialized = TRUE;
}
VOID
DnsIntCacheFree(VOID)
{
DPRINT("DnsIntCacheFree\n");
/* Check if we're initialized */
if (!DnsCacheInitialized)
return;
if (!DnsCache.RecordList.Flink)
return;
DnsIntCacheFlush();
DeleteCriticalSection(&DnsCache.Lock);
DnsCacheInitialized = FALSE;
}
VOID
DnsIntCacheRemoveEntryItem(PRESOLVER_CACHE_ENTRY CacheEntry)
{
DPRINT("DnsIntCacheRemoveEntryItem %p\n", CacheEntry);
/* Remove the entry from the list */
RemoveEntryList(&CacheEntry->CacheLink);
/* Free record */
DnsRecordListFree(CacheEntry->Record, DnsFreeRecordList);
/* Delete us */
HeapFree(GetProcessHeap(), 0, CacheEntry);
}
VOID
DnsIntCacheFlush(VOID)
{
PLIST_ENTRY Entry;
PRESOLVER_CACHE_ENTRY CacheEntry;
DPRINT("DnsIntCacheFlush\n");
/* Lock the cache */
DnsCacheLock();
/* Loop every entry */
Entry = DnsCache.RecordList.Flink;
while (Entry != &DnsCache.RecordList)
{
/* Get this entry */
CacheEntry = CONTAINING_RECORD(Entry, RESOLVER_CACHE_ENTRY, CacheLink);
/* Remove it from list */
DnsIntCacheRemoveEntryItem(CacheEntry);
/* Move to the next entry */
Entry = DnsCache.RecordList.Flink;
}
/* Unlock the cache */
DnsCacheUnlock();
}
BOOL
DnsIntCacheGetEntryFromName(LPCWSTR Name,
PDNS_RECORDW *Record)
{
BOOL Ret = FALSE;
PRESOLVER_CACHE_ENTRY CacheEntry;
PLIST_ENTRY NextEntry;
DPRINT("DnsIntCacheGetEntryFromName %ws %p\n", Name, Record);
/* Assume failure */
*Record = NULL;
/* Lock the cache */
DnsCacheLock();
/* Match the Id with all the entries in the List */
NextEntry = DnsCache.RecordList.Flink;
while (NextEntry != &DnsCache.RecordList)
{
/* Get the Current Entry */
CacheEntry = CONTAINING_RECORD(NextEntry, RESOLVER_CACHE_ENTRY, CacheLink);
/* Check if this is the Catalog Entry ID we want */
if (_wcsicmp(CacheEntry->Record->pName, Name) == 0)
{
/* Copy the entry and return it */
*Record = DnsRecordSetCopyEx(CacheEntry->Record, DnsCharSetUnicode, DnsCharSetUnicode);
Ret = TRUE;
break;
}
NextEntry = NextEntry->Flink;
}
/* Release the cache */
DnsCacheUnlock();
/* Return */
return Ret;
}
BOOL
DnsIntCacheRemoveEntryByName(LPCWSTR Name)
{
BOOL Ret = FALSE;
PRESOLVER_CACHE_ENTRY CacheEntry;
PLIST_ENTRY NextEntry;
DPRINT("DnsIntCacheRemoveEntryByName %ws\n", Name);
/* Lock the cache */
DnsCacheLock();
/* Match the Id with all the entries in the List */
NextEntry = DnsCache.RecordList.Flink;
while (NextEntry != &DnsCache.RecordList)
{
/* Get the Current Entry */
CacheEntry = CONTAINING_RECORD(NextEntry, RESOLVER_CACHE_ENTRY, CacheLink);
/* Check if this is the Catalog Entry ID we want */
if (_wcsicmp(CacheEntry->Record->pName, Name) == 0)
{
/* Remove the entry */
DnsIntCacheRemoveEntryItem(CacheEntry);
Ret = TRUE;
break;
}
NextEntry = NextEntry->Flink;
}
/* Release the cache */
DnsCacheUnlock();
/* Return */
return Ret;
}
VOID
DnsIntCacheAddEntry(PDNS_RECORDW Record)
{
PRESOLVER_CACHE_ENTRY Entry;
DPRINT("DnsIntCacheRemoveEntryByName %p\n", Record);
/* Lock the cache */
DnsCacheLock();
/* Match the Id with all the entries in the List */
Entry = (PRESOLVER_CACHE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(*Entry));
if (!Entry)
return;
Entry->Record = DnsRecordSetCopyEx(Record, DnsCharSetUnicode, DnsCharSetUnicode);
/* Insert it to our List */
InsertTailList(&DnsCache.RecordList, &Entry->CacheLink);
/* Release the cache */
DnsCacheUnlock();
}

View file

@ -0,0 +1,150 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS DNS Resolver
* FILE: base/services/dnsrslvr/dnsrslvr.c
* PURPOSE: DNS Resolver Service
* PROGRAMMER: Christoph von Wittich
*/
/* INCLUDES *****************************************************************/
#include "precomp.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ******************************************************************/
HINSTANCE hDllInstance;
SERVICE_STATUS_HANDLE ServiceStatusHandle;
SERVICE_STATUS SvcStatus;
static WCHAR ServiceName[] = L"Dnscache";
DWORD WINAPI RpcThreadRoutine(LPVOID lpParameter);
/* FUNCTIONS *****************************************************************/
static
VOID
UpdateServiceStatus(
HANDLE hServiceStatus,
DWORD NewStatus,
DWORD Increment)
{
if (Increment > 0)
SvcStatus.dwCheckPoint += Increment;
else
SvcStatus.dwCheckPoint = 0;
SvcStatus.dwCurrentState = NewStatus;
SetServiceStatus(hServiceStatus, &SvcStatus);
}
static
DWORD
WINAPI
ServiceControlHandler(
DWORD dwControl,
DWORD dwEventType,
LPVOID lpEventData,
LPVOID lpContext)
{
switch (dwControl)
{
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
UpdateServiceStatus(ServiceStatusHandle, SERVICE_STOP_PENDING, 1);
RpcMgmtStopServerListening(NULL);
DnsIntCacheFree();
UpdateServiceStatus(ServiceStatusHandle, SERVICE_STOPPED, 0);
break;
case SERVICE_CONTROL_INTERROGATE:
return NO_ERROR;
default:
return ERROR_CALL_NOT_IMPLEMENTED;
}
return NO_ERROR;
}
VOID
WINAPI
ServiceMain(
DWORD argc,
LPWSTR *argv)
{
HANDLE hThread;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
DPRINT("ServiceMain() called\n");
SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
SvcStatus.dwCurrentState = SERVICE_START_PENDING;
SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
SvcStatus.dwCheckPoint = 0;
SvcStatus.dwWin32ExitCode = NO_ERROR;
SvcStatus.dwServiceSpecificExitCode = 0;
SvcStatus.dwWaitHint = 4000;
ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
ServiceControlHandler,
NULL);
if (!ServiceStatusHandle)
{
DPRINT1("DNSRSLVR: Unable to register service control handler (%lx)\n", GetLastError());
return; // FALSE
}
DnsIntCacheInitialize();
hThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)
RpcThreadRoutine,
NULL,
0,
NULL);
if (!hThread)
{
DnsIntCacheFree();
DPRINT("Can't create RpcThread\n");
UpdateServiceStatus(ServiceStatusHandle, SERVICE_STOPPED, 0);
}
else
{
CloseHandle(hThread);
}
DPRINT("ServiceMain() done\n");
UpdateServiceStatus(ServiceStatusHandle, SERVICE_RUNNING, 0);
}
BOOL
WINAPI
DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ PVOID pvReserved)
{
UNREFERENCED_PARAMETER(pvReserved);
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
hDllInstance = hinstDLL;
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
/* EOF */

View file

@ -0,0 +1,4 @@
#define REACTOS_STR_FILE_DESCRIPTION "DNS-Client"
#define REACTOS_STR_INTERNAL_NAME "dnsrslvr"
#define REACTOS_STR_ORIGINAL_FILENAME "dnsrslvr.dll"
#include <reactos/version.rc>

View file

@ -0,0 +1 @@
@ stdcall ServiceMain(long ptr)

View file

@ -0,0 +1,45 @@
#ifndef _DNSRSLVR_PCH_
#define _DNSRSLVR_PCH_
#include <stdarg.h>
#define WIN32_NO_STATUS
#define _INC_WINDOWS
#define COM_NO_WINDOWS_H
#include <windef.h>
#include <winbase.h>
#include <winsvc.h>
#include <windns.h>
#include <ndk/rtlfuncs.h>
#include <ndk/obfuncs.h>
#include <dnsrslvr_s.h>
typedef struct _RESOLVER_CACHE_ENTRY
{
LIST_ENTRY CacheLink;
PDNS_RECORDW Record;
} RESOLVER_CACHE_ENTRY, *PRESOLVER_CACHE_ENTRY;
typedef struct _RESOLVER_CACHE
{
LIST_ENTRY RecordList;
CRITICAL_SECTION Lock;
} RESOLVER_CACHE, *PRESOLVER_CACHE;
/* cache.c */
VOID DnsIntCacheInitialize(VOID);
VOID DnsIntCacheRemoveEntryItem(PRESOLVER_CACHE_ENTRY CacheEntry);
VOID DnsIntCacheFree(VOID);
VOID DnsIntCacheFlush(VOID);
BOOL DnsIntCacheGetEntryFromName(LPCWSTR Name,
PDNS_RECORDW *Record);
VOID DnsIntCacheAddEntry(PDNS_RECORDW Record);
BOOL DnsIntCacheRemoveEntryByName(LPCWSTR Name);
#endif /* _DNSRSLVR_PCH_ */

View file

@ -0,0 +1,130 @@
/*
* PROJECT: ReactOS DNS Resolver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: base/services/dnsrslvr/rpcserver.c
* PURPOSE: RPC server interface
* COPYRIGHT: Copyright 2016 Christoph von Wittich
*/
#include "precomp.h"
#define NDEBUG
#include <debug.h>
DWORD
WINAPI
RpcThreadRoutine(LPVOID lpParameter)
{
RPC_STATUS Status;
Status = RpcServerUseProtseqEpW(L"ncalrpc", 20, L"DNSResolver", NULL);
if (Status != RPC_S_OK)
{
DPRINT("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
return 0;
}
Status = RpcServerRegisterIf(DnsResolver_v2_0_s_ifspec, NULL, NULL);
if (Status != RPC_S_OK)
{
DPRINT("RpcServerRegisterIf() failed (Status %lx)\n", Status);
return 0;
}
Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, 0);
if (Status != RPC_S_OK)
{
DPRINT("RpcServerListen() failed (Status %lx)\n", Status);
}
DPRINT("RpcServerListen finished\n");
return 0;
}
DWORD
R_ResolverFlushCache(
DNSRSLVR_HANDLE pwszServerName)
{
// FIXME Should store (and flush) entries by server handle
DnsIntCacheFlush();
return 0;
}
DWORD
R_ResolverQuery(
DNSRSLVR_HANDLE pwszServerName,
LPCWSTR pwsName,
WORD wType,
DWORD Flags,
DWORD *dwRecords,
DNS_RECORDW **ppResultRecords)
{
#if 0
DNS_QUERY_REQUEST QueryRequest = { 0 };
DNS_QUERY_RESULT QueryResults = { 0 };
#endif
DNS_STATUS Status;
PDNS_RECORDW Record;
DPRINT1("R_ResolverQuery %p %p %x %lx %p %p\n",
pwszServerName, pwsName, wType, Flags, dwRecords, ppResultRecords);
if (!pwszServerName || !pwsName || !wType || !ppResultRecords)
return ERROR_INVALID_PARAMETER;
// FIXME Should lookup entries by server handle
if (DnsIntCacheGetEntryFromName(pwsName, ppResultRecords))
{
Status = ERROR_SUCCESS;
}
else
{
#if 0
QueryRequest.Version = DNS_QUERY_REQUEST_VERSION1;
QueryRequest.QueryType = wType;
QueryRequest.QueryName = pwsName;
QueryRequest.QueryOptions = Flags;
QueryResults.Version = DNS_QUERY_REQUEST_VERSION1;
Status = DnsQueryEx(&QueryRequest, &QueryResults, NULL);
if (Status == ERROR_SUCCESS)
{
// FIXME Should store (and flush) entries by server handle
DnsIntCacheAddEntry(QueryResults.pQueryRecords);
*ppResultRecords = QueryResults.pQueryRecords;
}
#endif
}
if (dwRecords)
*dwRecords = 0;
if (Status == ERROR_SUCCESS)
{
Record = *ppResultRecords;
while (Record)
{
if (dwRecords)
(*dwRecords)++;
Record = Record->pNext;
}
}
DPRINT1("R_ResolverQuery result %ld %ld\n", Status, *dwRecords);
return Status;
}
void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
{
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
}
void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
{
HeapFree(GetProcessHeap(), 0, ptr);
}
void __RPC_USER WLANSVC_RPC_HANDLE_rundown(DNSRSLVR_HANDLE hClientHandle)
{
}

View file

@ -27,7 +27,7 @@ AddReg = TCPIP_AddReg_Global.NT
HKR,"Ndi","ClsId",0x00000000,"{A907657F-6FDF-11D0-8EFB-00C04FD912B2}"
HKR,"Ndi","HelpText",0x00000000,"Transmission Control Protocol/Internet Protocol"
HKR,"Ndi","Service",0x00000000,"Tcpip"
HKR,"Ndi","CoServices",0x00010000,"Tcpip","Dhcp"
HKR,"Ndi","CoServices",0x00010000,"Tcpip","Dhcp","Dnscache"
; TCP/IPv4 driver
; NOTE: These settings should be added by the network setup
@ -236,6 +236,7 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Winsock2\Parameters\Protocol_Catalog9\Ca
[MS_TCPIP.PrimaryInstall.Services]
AddService = Tcpip, , tcpip_Service_Inst
AddService = DHCP, , dhcp_Service_Inst
AddService = Dnscache, , dns_Service_Inst
[tcpip_Service_Inst]
ServiceType = 1
@ -275,6 +276,20 @@ AddReg=dhcp_AddReg
HKR,,"ObjectName",0x00000000,"LocalSystem"
HKR,"Parameters","ServiceDll",0x00020000,"%SystemRoot%\system32\dhcpcsvc.dll"
[dns_Service_Inst]
DisplayName = "DNS Client"
Description = "Service that caches local DNS queries"
ServiceType = 0x20
StartType = 2
ErrorControl = 1
ServiceBinary = "%11%\svchost.exe -k netsvcs"
LoadOrderGroup = TDI
AddReg=dns_AddReg
[dns_AddReg]
HKR,,"ObjectName",0x00000000,"LocalSystem"
HKR,"Parameters","ServiceDll",0x00020000,"%SystemRoot%\system32\dnsrslvr.dll"
;-------------------------------- STRINGS -------------------------------
[Strings]

View file

@ -6,7 +6,10 @@
#define UNICODE
#include <sal.h>
cpp_quote("#ifndef _WINDNS_INCLUDED_")
#include <windns.h>
cpp_quote("#endif")
typedef [handle, string] LPWSTR DNSRSLVR_HANDLE;

View file

@ -14,6 +14,10 @@ typedef struct _DNS_CACHE_ENTRY
unsigned short wFlags; /* DNS Record Flags */
} DNS_CACHE_ENTRY, *PDNS_CACHE_ENTRY;
#ifndef __WIDL__
// Hack
BOOL
WINAPI
DnsFlushResolverCache(VOID);
@ -23,6 +27,8 @@ WINAPI
DnsGetCacheDataTable(
_Out_ PDNS_CACHE_ENTRY *DnsCache);
#endif /* __WIDL__ */
#ifdef __cplusplus
}
#endif