Index: base/services/dnsrslvr/CMakeLists.txt =================================================================== --- base/services/dnsrslvr/CMakeLists.txt (revision 0) +++ base/services/dnsrslvr/CMakeLists.txt (working copy) @@ -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) Property changes on: base/services/dnsrslvr/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: base/services/dnsrslvr/cache.c =================================================================== --- base/services/dnsrslvr/cache.c (revision 0) +++ base/services/dnsrslvr/cache.c (working copy) @@ -0,0 +1,186 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: base/services/dnsrslvr/cache.c + * PURPOSE: DNS cache functions. + * PROGRAMER: Peter Hater + */ + +#include "precomp.h" +#include + +//#define NDEBUG +#include + +static DNS_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 catalog 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(PDNS_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 */ + RtlFreeHeap(RtlGetProcessHeap(), 0, CacheEntry); +} + +VOID +DnsIntCacheFlush(VOID) +{ + PLIST_ENTRY Entry; + PDNS_CACHE_ENTRY CacheEntry; + + DPRINT("DnsIntCacheFlush\n"); + /* Acquire lock */ + DnsCacheLock(); + + /* Loop every entry */ + Entry = DnsCache.RecordList.Flink; + while (Entry != &DnsCache.RecordList) + { + /* Get this entry */ + CacheEntry = CONTAINING_RECORD(Entry, DNS_CACHE_ENTRY, CacheLink); + + /* Remove it from list */ + DnsIntCacheRemoveEntryItem(CacheEntry); + + /* Move to the next entry */ + Entry = DnsCache.RecordList.Flink; + } + + /* Release and delete the lock */ + DnsCacheUnlock(); +} + +BOOL +DnsIntCacheGetEntryFromName(LPCWSTR Name, + PDNS_RECORDW *Record) +{ + BOOL Ret = FALSE; + PDNS_CACHE_ENTRY Entry; + PLIST_ENTRY NextEntry = DnsCache.RecordList.Flink; + + 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 */ + do + { + /* Get the Current Entry */ + Entry = CONTAINING_RECORD(NextEntry, DNS_CACHE_ENTRY, CacheLink); + NextEntry = NextEntry->Flink; + + /* Check if this is the Catalog Entry ID we want */ + if (_wcsicmp(Entry->Record->pName, Name) == 0) + { + /* Copy the entry and return it */ + *Record = DnsRecordSetCopyEx(Entry->Record, DnsCharSetUnicode, DnsCharSetUnicode); + Ret = TRUE; + break; + } + } while (NextEntry != &DnsCache.RecordList); + + /* Release the catalog */ + DnsCacheUnlock(); + + /* Return */ + return Ret; +} + +BOOL +DnsIntCacheRemoveEntryByName(LPCWSTR Name) +{ + BOOL Ret = FALSE; + PDNS_CACHE_ENTRY Entry; + PLIST_ENTRY NextEntry = DnsCache.RecordList.Flink; + + DPRINT("DnsIntCacheRemoveEntryByName %ws\n", Name); + /* Lock the cache */ + DnsCacheLock(); + + /* Match the Id with all the entries in the List */ + do + { + /* Get the Current Entry */ + Entry = CONTAINING_RECORD(NextEntry, DNS_CACHE_ENTRY, CacheLink); + NextEntry = NextEntry->Flink; + + /* Check if this is the Catalog Entry ID we want */ + if (_wcsicmp(Entry->Record->pName, Name) == 0) + { + /* Copy the entry and return it */ + DnsIntCacheRemoveEntryItem(Entry); + Ret = TRUE; + break; + } + } while (NextEntry != &DnsCache.RecordList); + + /* Release the catalog */ + DnsCacheUnlock(); + + /* Return */ + return Ret; +} + +VOID +DnsIntCacheAddEntry(PDNS_RECORDW Record) +{ + PDNS_CACHE_ENTRY Entry; + + DPRINT("DnsIntCacheRemoveEntryByName %p\n", Record); + /* Lock the cache */ + DnsCacheLock(); + + /* Match the Id with all the entries in the List */ + Entry = (PDNS_CACHE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(*Entry)); + if (!Entry) + return; + Entry->Record = DnsRecordSetCopyEx(Record, DnsCharSetUnicode, DnsCharSetUnicode); + + /* Insert it to our List */ + InsertTailList(&DnsCache.RecordList, &Entry->CacheLink); + + /* Release the catalog */ + DnsCacheUnlock(); +} Index: base/services/dnsrslvr/dnsrslvr.c =================================================================== --- base/services/dnsrslvr/dnsrslvr.c (revision 0) +++ base/services/dnsrslvr/dnsrslvr.c (working copy) @@ -0,0 +1,138 @@ +/* + * 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 + +/* GLOBALS ******************************************************************/ + +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); +} + +int +wmain(int argc, WCHAR *argv[]) +{ + SERVICE_TABLE_ENTRYW ServiceTable[2] = + { + {ServiceName, ServiceMain}, + {NULL, NULL} + }; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + DPRINT("dnsrslvr: main() started\n"); + + StartServiceCtrlDispatcherW(ServiceTable); + + DPRINT("dnsrslvr: main() done\n"); + + ExitThread(0); + + return 0; +} + +/* EOF */ Property changes on: base/services/dnsrslvr/dnsrslvr.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: base/services/dnsrslvr/dnsrslvr.h =================================================================== --- base/services/dnsrslvr/dnsrslvr.h (revision 0) +++ base/services/dnsrslvr/dnsrslvr.h (working copy) @@ -0,0 +1,97 @@ +#ifndef DNSRSLVR_INTERNAL_H +#define DNSRSLVR_INTERNAL_H + +typedef struct _DNS_CACHE_ENTRY +{ + LIST_ENTRY CacheLink; + PDNS_RECORDW Record; +} DNS_CACHE_ENTRY, *PDNS_CACHE_ENTRY; + +typedef struct _DNS_CACHE +{ + LIST_ENTRY RecordList; + CRITICAL_SECTION Lock; +} DNS_CACHE, *PDNS_CACHE; + +VOID DnsIntCacheInitialize(VOID); +VOID DnsIntCacheRemoveEntryItem(PDNS_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); + + +#define DNS_QUERY_RESULTS_VERSION1 0x1 + +typedef struct _DNS_QUERY_RESULT +{ + ULONG Version; + DNS_STATUS QueryStatus; + ULONG64 QueryOptions; + PDNS_RECORDW pQueryRecords; + PVOID Reserved; +} +DNS_QUERY_RESULT, *PDNS_QUERY_RESULT; + +typedef +VOID +WINAPI +DNS_QUERY_COMPLETION_ROUTINE( + PVOID pQueryContext, + PDNS_QUERY_RESULT pQueryResults +); + +typedef DNS_QUERY_COMPLETION_ROUTINE *PDNS_QUERY_COMPLETION_ROUTINE; + +#define DNS_QUERY_REQUEST_VERSION1 0x1 + +typedef struct _DNS_QUERY_REQUEST +{ + ULONG Version; + PCWSTR QueryName; + WORD QueryType; + ULONG64 QueryOptions; + PDNS_ADDR_ARRAY pDnsServerList; + ULONG InterfaceIndex; + PDNS_QUERY_COMPLETION_ROUTINE pQueryCompletionCallback; + PVOID pQueryContext; +} +DNS_QUERY_REQUEST, *PDNS_QUERY_REQUEST; + +typedef struct _DNS_QUERY_CANCEL +{ + CHAR Reserved[32]; +} +DNS_QUERY_CANCEL, *PDNS_QUERY_CANCEL; + +DNS_STATUS +WINAPI +DnsQueryEx( + PDNS_QUERY_REQUEST pQueryRequest, + PDNS_QUERY_RESULT pQueryResults, + PDNS_QUERY_CANCEL pCancelHandle +); + +DNS_STATUS +WINAPI +DnsCancelQuery( + PDNS_QUERY_CANCEL pCancelHandle +); + +VOID +WINAPI +DnsRecordListFree( + PDNS_RECORDW list, + DNS_FREE_TYPE type +); + +PDNS_RECORDW +WINAPI +DnsRecordSetCopyEx( + _In_ PDNS_RECORDW pRecordSet, + _In_ DNS_CHARSET CharSetIn, + _In_ DNS_CHARSET CharSetOut); + +#endif /* DNSRSLVR_INTERNAL_H */ Index: base/services/dnsrslvr/dnsrslvr.rc =================================================================== --- base/services/dnsrslvr/dnsrslvr.rc (revision 0) +++ base/services/dnsrslvr/dnsrslvr.rc (working copy) @@ -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 Property changes on: base/services/dnsrslvr/dnsrslvr.rc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: base/services/dnsrslvr/dnsrslvr.spec =================================================================== --- base/services/dnsrslvr/dnsrslvr.spec (revision 0) +++ base/services/dnsrslvr/dnsrslvr.spec (working copy) @@ -0,0 +1 @@ +@ stdcall ServiceMain(long ptr) \ No newline at end of file Index: base/services/dnsrslvr/precomp.h =================================================================== --- base/services/dnsrslvr/precomp.h (revision 0) +++ base/services/dnsrslvr/precomp.h (working copy) @@ -0,0 +1,20 @@ +#ifndef _DNSRSLVR_PCH_ +#define _DNSRSLVR_PCH_ + +#include + +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H + +#include +#include +#include +#include + +#include +#include + +#include "dnsrslvr.h" + +#endif /* _DNSRSLVR_PCH_ */ Property changes on: base/services/dnsrslvr/precomp.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: base/services/dnsrslvr/rpcserver.c =================================================================== --- base/services/dnsrslvr/rpcserver.c (revision 0) +++ base/services/dnsrslvr/rpcserver.c (working copy) @@ -0,0 +1,114 @@ +/* + * 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 + +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) +{ + DNS_QUERY_REQUEST QueryRequest = { 0 }; + DNS_QUERY_RESULT QueryResults = { 0 }; + DNS_STATUS Status; + PDNS_RECORDW Record; + + DPRINT("R_ResolverQuery %p %p %x %lx %p %p\n", pwszServerName, pwsName, wType, Flags, dwRecords, ppResultRecords); + if (!pwszServerName || !pwsName || !wType || !ppResultRecords) + return ERROR_INVALID_PARAMETER; + QueryRequest.Version = DNS_QUERY_REQUEST_VERSION1; + QueryRequest.QueryType = wType; + QueryRequest.QueryName = pwsName; + QueryRequest.QueryOptions = Flags; + QueryResults.Version = DNS_QUERY_REQUEST_VERSION1; + // FIXME Should lookup entries by server handle + if (DnsIntCacheGetEntryFromName(pwsName, ppResultRecords)) + { + Status = ERROR_SUCCESS; + } + else + { + Status = DnsQueryEx(&QueryRequest, &QueryResults, NULL); + if (Status == ERROR_SUCCESS) + { + // FIXME Should store (and flush) entries by server handle + DnsIntCacheAddEntry(QueryResults.pQueryRecords); + *ppResultRecords = QueryResults.pQueryRecords; + } + } + if (dwRecords) *dwRecords = 0; + + if (Status == ERROR_SUCCESS) + { + Record = *ppResultRecords; + while (Record) + { + if (dwRecords) (*dwRecords)++; + Record = Record->pNext; + } + } + DPRINT("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) +{ +} + Property changes on: base/services/dnsrslvr/rpcserver.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: base/services/dnsrslvr/cache.c =================================================================== --- base/services/dnsrslvr/cache.c (revision 0) +++ base/services/dnsrslvr/cache.c (working copy) @@ -0,0 +1,186 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: base/services/dnsrslvr/cache.c + * PURPOSE: DNS cache functions. + * PROGRAMER: Peter Hater + */ + +#include "precomp.h" +#include + +//#define NDEBUG +#include + +static DNS_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 catalog 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(PDNS_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 */ + RtlFreeHeap(RtlGetProcessHeap(), 0, CacheEntry); +} + +VOID +DnsIntCacheFlush(VOID) +{ + PLIST_ENTRY Entry; + PDNS_CACHE_ENTRY CacheEntry; + + DPRINT("DnsIntCacheFlush\n"); + /* Acquire lock */ + DnsCacheLock(); + + /* Loop every entry */ + Entry = DnsCache.RecordList.Flink; + while (Entry != &DnsCache.RecordList) + { + /* Get this entry */ + CacheEntry = CONTAINING_RECORD(Entry, DNS_CACHE_ENTRY, CacheLink); + + /* Remove it from list */ + DnsIntCacheRemoveEntryItem(CacheEntry); + + /* Move to the next entry */ + Entry = DnsCache.RecordList.Flink; + } + + /* Release and delete the lock */ + DnsCacheUnlock(); +} + +BOOL +DnsIntCacheGetEntryFromName(LPCWSTR Name, + PDNS_RECORDW *Record) +{ + BOOL Ret = FALSE; + PDNS_CACHE_ENTRY Entry; + PLIST_ENTRY NextEntry = DnsCache.RecordList.Flink; + + 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 */ + do + { + /* Get the Current Entry */ + Entry = CONTAINING_RECORD(NextEntry, DNS_CACHE_ENTRY, CacheLink); + NextEntry = NextEntry->Flink; + + /* Check if this is the Catalog Entry ID we want */ + if (_wcsicmp(Entry->Record->pName, Name) == 0) + { + /* Copy the entry and return it */ + *Record = DnsRecordSetCopyEx(Entry->Record, DnsCharSetUnicode, DnsCharSetUnicode); + Ret = TRUE; + break; + } + } while (NextEntry != &DnsCache.RecordList); + + /* Release the catalog */ + DnsCacheUnlock(); + + /* Return */ + return Ret; +} + +BOOL +DnsIntCacheRemoveEntryByName(LPCWSTR Name) +{ + BOOL Ret = FALSE; + PDNS_CACHE_ENTRY Entry; + PLIST_ENTRY NextEntry = DnsCache.RecordList.Flink; + + DPRINT("DnsIntCacheRemoveEntryByName %ws\n", Name); + /* Lock the cache */ + DnsCacheLock(); + + /* Match the Id with all the entries in the List */ + do + { + /* Get the Current Entry */ + Entry = CONTAINING_RECORD(NextEntry, DNS_CACHE_ENTRY, CacheLink); + NextEntry = NextEntry->Flink; + + /* Check if this is the Catalog Entry ID we want */ + if (_wcsicmp(Entry->Record->pName, Name) == 0) + { + /* Copy the entry and return it */ + DnsIntCacheRemoveEntryItem(Entry); + Ret = TRUE; + break; + } + } while (NextEntry != &DnsCache.RecordList); + + /* Release the catalog */ + DnsCacheUnlock(); + + /* Return */ + return Ret; +} + +VOID +DnsIntCacheAddEntry(PDNS_RECORDW Record) +{ + PDNS_CACHE_ENTRY Entry; + + DPRINT("DnsIntCacheRemoveEntryByName %p\n", Record); + /* Lock the cache */ + DnsCacheLock(); + + /* Match the Id with all the entries in the List */ + Entry = (PDNS_CACHE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(*Entry)); + if (!Entry) + return; + Entry->Record = DnsRecordSetCopyEx(Record, DnsCharSetUnicode, DnsCharSetUnicode); + + /* Insert it to our List */ + InsertTailList(&DnsCache.RecordList, &Entry->CacheLink); + + /* Release the catalog */ + DnsCacheUnlock(); +} Index: base/services/dnsrslvr/CMakeLists.txt =================================================================== --- base/services/dnsrslvr/CMakeLists.txt (revision 0) +++ base/services/dnsrslvr/CMakeLists.txt (working copy) @@ -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) Property changes on: base/services/dnsrslvr/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: base/services/dnsrslvr/dnsrslvr.c =================================================================== --- base/services/dnsrslvr/dnsrslvr.c (revision 0) +++ base/services/dnsrslvr/dnsrslvr.c (working copy) @@ -0,0 +1,138 @@ +/* + * 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 + +/* GLOBALS ******************************************************************/ + +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); +} + +int +wmain(int argc, WCHAR *argv[]) +{ + SERVICE_TABLE_ENTRYW ServiceTable[2] = + { + {ServiceName, ServiceMain}, + {NULL, NULL} + }; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + DPRINT("dnsrslvr: main() started\n"); + + StartServiceCtrlDispatcherW(ServiceTable); + + DPRINT("dnsrslvr: main() done\n"); + + ExitThread(0); + + return 0; +} + +/* EOF */ Property changes on: base/services/dnsrslvr/dnsrslvr.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: base/services/dnsrslvr/dnsrslvr.h =================================================================== --- base/services/dnsrslvr/dnsrslvr.h (revision 0) +++ base/services/dnsrslvr/dnsrslvr.h (working copy) @@ -0,0 +1,97 @@ +#ifndef DNSRSLVR_INTERNAL_H +#define DNSRSLVR_INTERNAL_H + +typedef struct _DNS_CACHE_ENTRY +{ + LIST_ENTRY CacheLink; + PDNS_RECORDW Record; +} DNS_CACHE_ENTRY, *PDNS_CACHE_ENTRY; + +typedef struct _DNS_CACHE +{ + LIST_ENTRY RecordList; + CRITICAL_SECTION Lock; +} DNS_CACHE, *PDNS_CACHE; + +VOID DnsIntCacheInitialize(VOID); +VOID DnsIntCacheRemoveEntryItem(PDNS_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); + + +#define DNS_QUERY_RESULTS_VERSION1 0x1 + +typedef struct _DNS_QUERY_RESULT +{ + ULONG Version; + DNS_STATUS QueryStatus; + ULONG64 QueryOptions; + PDNS_RECORDW pQueryRecords; + PVOID Reserved; +} +DNS_QUERY_RESULT, *PDNS_QUERY_RESULT; + +typedef +VOID +WINAPI +DNS_QUERY_COMPLETION_ROUTINE( + PVOID pQueryContext, + PDNS_QUERY_RESULT pQueryResults +); + +typedef DNS_QUERY_COMPLETION_ROUTINE *PDNS_QUERY_COMPLETION_ROUTINE; + +#define DNS_QUERY_REQUEST_VERSION1 0x1 + +typedef struct _DNS_QUERY_REQUEST +{ + ULONG Version; + PCWSTR QueryName; + WORD QueryType; + ULONG64 QueryOptions; + PDNS_ADDR_ARRAY pDnsServerList; + ULONG InterfaceIndex; + PDNS_QUERY_COMPLETION_ROUTINE pQueryCompletionCallback; + PVOID pQueryContext; +} +DNS_QUERY_REQUEST, *PDNS_QUERY_REQUEST; + +typedef struct _DNS_QUERY_CANCEL +{ + CHAR Reserved[32]; +} +DNS_QUERY_CANCEL, *PDNS_QUERY_CANCEL; + +DNS_STATUS +WINAPI +DnsQueryEx( + PDNS_QUERY_REQUEST pQueryRequest, + PDNS_QUERY_RESULT pQueryResults, + PDNS_QUERY_CANCEL pCancelHandle +); + +DNS_STATUS +WINAPI +DnsCancelQuery( + PDNS_QUERY_CANCEL pCancelHandle +); + +VOID +WINAPI +DnsRecordListFree( + PDNS_RECORDW list, + DNS_FREE_TYPE type +); + +PDNS_RECORDW +WINAPI +DnsRecordSetCopyEx( + _In_ PDNS_RECORDW pRecordSet, + _In_ DNS_CHARSET CharSetIn, + _In_ DNS_CHARSET CharSetOut); + +#endif /* DNSRSLVR_INTERNAL_H */ Index: base/services/dnsrslvr/dnsrslvr.rc =================================================================== --- base/services/dnsrslvr/dnsrslvr.rc (revision 0) +++ base/services/dnsrslvr/dnsrslvr.rc (working copy) @@ -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 Property changes on: base/services/dnsrslvr/dnsrslvr.rc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: base/services/dnsrslvr/dnsrslvr.spec =================================================================== --- base/services/dnsrslvr/dnsrslvr.spec (revision 0) +++ base/services/dnsrslvr/dnsrslvr.spec (working copy) @@ -0,0 +1 @@ +@ stdcall ServiceMain(long ptr) \ No newline at end of file Index: base/services/dnsrslvr/precomp.h =================================================================== --- base/services/dnsrslvr/precomp.h (revision 0) +++ base/services/dnsrslvr/precomp.h (working copy) @@ -0,0 +1,20 @@ +#ifndef _DNSRSLVR_PCH_ +#define _DNSRSLVR_PCH_ + +#include + +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H + +#include +#include +#include +#include + +#include +#include + +#include "dnsrslvr.h" + +#endif /* _DNSRSLVR_PCH_ */ Property changes on: base/services/dnsrslvr/precomp.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: base/services/dnsrslvr/rpcserver.c =================================================================== --- base/services/dnsrslvr/rpcserver.c (revision 0) +++ base/services/dnsrslvr/rpcserver.c (working copy) @@ -0,0 +1,114 @@ +/* + * 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 + +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) +{ + DNS_QUERY_REQUEST QueryRequest = { 0 }; + DNS_QUERY_RESULT QueryResults = { 0 }; + DNS_STATUS Status; + PDNS_RECORDW Record; + + DPRINT("R_ResolverQuery %p %p %x %lx %p %p\n", pwszServerName, pwsName, wType, Flags, dwRecords, ppResultRecords); + if (!pwszServerName || !pwsName || !wType || !ppResultRecords) + return ERROR_INVALID_PARAMETER; + QueryRequest.Version = DNS_QUERY_REQUEST_VERSION1; + QueryRequest.QueryType = wType; + QueryRequest.QueryName = pwsName; + QueryRequest.QueryOptions = Flags; + QueryResults.Version = DNS_QUERY_REQUEST_VERSION1; + // FIXME Should lookup entries by server handle + if (DnsIntCacheGetEntryFromName(pwsName, ppResultRecords)) + { + Status = ERROR_SUCCESS; + } + else + { + Status = DnsQueryEx(&QueryRequest, &QueryResults, NULL); + if (Status == ERROR_SUCCESS) + { + // FIXME Should store (and flush) entries by server handle + DnsIntCacheAddEntry(QueryResults.pQueryRecords); + *ppResultRecords = QueryResults.pQueryRecords; + } + } + if (dwRecords) *dwRecords = 0; + + if (Status == ERROR_SUCCESS) + { + Record = *ppResultRecords; + while (Record) + { + if (dwRecords) (*dwRecords)++; + Record = Record->pNext; + } + } + DPRINT("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) +{ +} + Property changes on: base/services/dnsrslvr/rpcserver.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: boot/bootdata/hivesft.inf =================================================================== --- boot/bootdata/hivesft.inf (revision 74743) +++ boot/bootdata/hivesft.inf (working copy) @@ -1654,7 +1654,7 @@ ; SvcHost services HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost",,0x00000012 HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost","DcomLaunch",0x00010000,"PlugPlay" -HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost","netsvcs",0x00010000,"DHCP","BITS","lanmanserver","lanmanworkstation","Schedule","Themes","winmgmt" +HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost","netsvcs",0x00010000,"DHCP","BITS","lanmanserver","lanmanworkstation","Schedule","Themes","winmgmt","DNSCache" ; Win32 config HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows",,0x00000012 Index: dll/win32/dnsapi/CMakeLists.txt =================================================================== --- dll/win32/dnsapi/CMakeLists.txt (revision 74743) +++ dll/win32/dnsapi/CMakeLists.txt (working copy) @@ -2,8 +2,10 @@ include_directories( include ${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/adns/src - ${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/adns/adns_win32) + ${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/adns/adns_win32 + ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl) +add_rpc_files(client ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl/dnsrslvr.idl) add_definitions(-DADNS_JGAA_WIN32) spec2def(dnsapi.dll dnsapi.spec ADD_IMPORTLIB) @@ -19,11 +21,13 @@ add_library(dnsapi SHARED ${SOURCE} + dnsapi/rpc.c + ${CMAKE_CURRENT_BINARY_DIR}/dnsrslvr_c.c dnsapi.rc ${CMAKE_CURRENT_BINARY_DIR}/dnsapi.def) set_module_type(dnsapi win32dll) -target_link_libraries(dnsapi adns) -add_importlibs(dnsapi advapi32 user32 ws2_32 iphlpapi msvcrt kernel32 ntdll) +target_link_libraries(dnsapi adns ${PSEH_LIB}) +add_importlibs(dnsapi advapi32 user32 ws2_32 iphlpapi rpcrt4 msvcrt kernel32 ntdll) add_pch(dnsapi dnsapi/precomp.h SOURCE) add_cd_file(TARGET dnsapi DESTINATION reactos/system32 FOR all) Index: dll/win32/dnsapi/dnsapi.spec =================================================================== --- dll/win32/dnsapi/dnsapi.spec (revision 74743) +++ dll/win32/dnsapi/dnsapi.spec (working copy) @@ -13,6 +13,7 @@ @ stdcall DnsAsyncRegisterHostAddrs_W() @ stdcall DnsAsyncRegisterInit() @ stdcall DnsAsyncRegisterTerm() +@ stdcall DnsCancelQuery(ptr) @ stdcall DnsCheckNameCollision_A() @ stdcall DnsCheckNameCollision_UTF8() @ stdcall DnsCheckNameCollision_W() @@ -80,7 +81,7 @@ @ stdcall DnsNotifyResolver() @ stdcall DnsQuery_A(str long long ptr ptr ptr) @ stdcall DnsQueryConfig(long long wstr ptr ptr ptr) -@ stdcall DnsQueryEx() +@ stdcall DnsQueryEx(ptr ptr ptr) @ stdcall DnsQuery_UTF8(str long long ptr ptr ptr) @ stdcall DnsQuery_W(wstr long long ptr ptr ptr) @ stdcall DnsRecordBuild_UTF8() Index: dll/win32/dnsapi/dnsapi/query.c =================================================================== --- dll/win32/dnsapi/dnsapi/query.c (revision 74743) +++ dll/win32/dnsapi/dnsapi/query.c (working copy) @@ -16,6 +16,21 @@ #define NDEBUG #include +DNS_STATUS WINAPI +GetCurrentTimeInSeconds() +{ + FILETIME Time; + FILETIME Adjustment; + ULARGE_INTEGER lTime,lAdj; + SYSTEMTIME st = { 1970,1,0,1,0,0,0 }; + SystemTimeToFileTime(&st, &Adjustment); + memcpy(&lAdj, &Adjustment, sizeof(lAdj)); + GetSystemTimeAsFileTime(&Time); + memcpy(&lTime, &Time, sizeof(lTime)); + lTime.QuadPart -= lAdj.QuadPart; + return (DWORD)(lTime.QuadPart/10000000LLU); +} + /* DnsQuery **************************** * Begin a DNS query, and allow the result to be placed in the application * supplied result pointer. The result can be manipulated with the record @@ -46,10 +61,12 @@ 0, NULL, 0); - if (AnsiLen == 0) + if (!AnsiLen) + { return NULL; + } AnsiString = RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen); - if (AnsiString == NULL) + if (!AnsiString) { return NULL; } @@ -75,11 +92,13 @@ -1, NULL, 0); - if (WideLen == 0) + if (!WideLen) + { return NULL; + } WideLen *= sizeof(WCHAR); WideString = RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen); - if (WideString == NULL) + if (!WideString) { return NULL; } @@ -97,7 +116,7 @@ DnsQuery_A(LPCSTR Name, WORD Type, DWORD Options, - PIP4_ARRAY Servers, + PVOID pExtra, PDNS_RECORD *QueryResultSet, PVOID *Reserved) { @@ -104,17 +123,15 @@ UINT i; PWCHAR Buffer; DNS_STATUS Status; - PDNS_RECORD QueryResultWide; - PDNS_RECORD ConvertedRecord = 0, LastRecord = 0; + PDNS_RECORDW QueryResultWide; + PDNS_RECORDA ConvertedRecord = 0, LastRecord = 0; - if (Name == NULL) + if (Name == NULL || QueryResultSet == NULL) return ERROR_INVALID_PARAMETER; - if (QueryResultSet == NULL) - return ERROR_INVALID_PARAMETER; Buffer = DnsCToW(Name); - Status = DnsQuery_W(Buffer, Type, Options, Servers, &QueryResultWide, Reserved); + Status = DnsQuery_W(Buffer, Type, Options, pExtra, (PDNS_RECORD *)&QueryResultWide, Reserved); while (Status == ERROR_SUCCESS && QueryResultWide) { @@ -122,8 +139,8 @@ { case DNS_TYPE_A: case DNS_TYPE_WKS: - ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); - ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName); + ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORDA)); + ConvertedRecord->pName = DnsWToC(QueryResultWide->pName); ConvertedRecord->wType = QueryResultWide->wType; ConvertedRecord->wDataLength = QueryResultWide->wDataLength; memcpy(&ConvertedRecord->Data, &QueryResultWide->Data, QueryResultWide->wDataLength); @@ -137,46 +154,46 @@ case DNS_TYPE_MF: case DNS_TYPE_MG: case DNS_TYPE_MR: - ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); - ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName); + ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORDA)); + ConvertedRecord->pName = DnsWToC(QueryResultWide->pName); ConvertedRecord->wType = QueryResultWide->wType; - ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATA); - ConvertedRecord->Data.PTR.pNameHost = DnsWToC((PWCHAR)QueryResultWide->Data.PTR.pNameHost); + ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATAA); + ConvertedRecord->Data.PTR.pNameHost = DnsWToC(QueryResultWide->Data.PTR.pNameHost); break; case DNS_TYPE_MINFO: - ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); - ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName); + ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORDA)); + ConvertedRecord->pName = DnsWToC(QueryResultWide->pName); ConvertedRecord->wType = QueryResultWide->wType; ConvertedRecord->wDataLength = sizeof(DNS_MINFO_DATA); - ConvertedRecord->Data.MINFO.pNameMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameMailbox); - ConvertedRecord->Data.MINFO.pNameErrorsMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameErrorsMailbox); + ConvertedRecord->Data.MINFO.pNameMailbox = DnsWToC(QueryResultWide->Data.MINFO.pNameMailbox); + ConvertedRecord->Data.MINFO.pNameErrorsMailbox = DnsWToC(QueryResultWide->Data.MINFO.pNameErrorsMailbox); break; case DNS_TYPE_MX: - ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); - ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName); + ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORDA)); + ConvertedRecord->pName = DnsWToC(QueryResultWide->pName); ConvertedRecord->wType = QueryResultWide->wType; ConvertedRecord->wDataLength = sizeof(DNS_MX_DATA); - ConvertedRecord->Data.MX.pNameExchange = DnsWToC((PWCHAR)QueryResultWide->Data.MX.pNameExchange); + ConvertedRecord->Data.MX.pNameExchange = DnsWToC(QueryResultWide->Data.MX.pNameExchange); ConvertedRecord->Data.MX.wPreference = QueryResultWide->Data.MX.wPreference; break; case DNS_TYPE_HINFO: - ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATA) + QueryResultWide->Data.TXT.dwStringCount); - ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName); + ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATAA) + QueryResultWide->Data.TXT.dwStringCount); + ConvertedRecord->pName = DnsWToC(QueryResultWide->pName); ConvertedRecord->wType = QueryResultWide->wType; - ConvertedRecord->wDataLength = sizeof(DNS_TXT_DATA) + (sizeof(PCHAR) * QueryResultWide->Data.TXT.dwStringCount); + ConvertedRecord->wDataLength = sizeof(DNS_TXT_DATAA) + (sizeof(PCHAR) * QueryResultWide->Data.TXT.dwStringCount); ConvertedRecord->Data.TXT.dwStringCount = QueryResultWide->Data.TXT.dwStringCount; for (i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++) - ConvertedRecord->Data.TXT.pStringArray[i] = DnsWToC((PWCHAR)QueryResultWide->Data.TXT.pStringArray[i]); + ConvertedRecord->Data.TXT.pStringArray[i] = DnsWToC(QueryResultWide->Data.TXT.pStringArray[i]); break; case DNS_TYPE_NULL: ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount); - ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName); + ConvertedRecord->pName = DnsWToC(QueryResultWide->pName); ConvertedRecord->wType = QueryResultWide->wType; ConvertedRecord->wDataLength = sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount; ConvertedRecord->Data.Null.dwByteCount = QueryResultWide->Data.Null.dwByteCount; @@ -203,7 +220,7 @@ /* The name */ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); /* The result*/ - if (QueryResultWide) DnsIntFreeRecordList(QueryResultWide); + if (QueryResultWide) DnsIntFreeRecordList((PDNS_RECORD)QueryResultWide); return Status; } @@ -345,11 +362,11 @@ IP4_ADDRESS ret = 0, Address; PIP_ADAPTER_ADDRESSES Addresses = NULL, pip; BOOL Found = FALSE; + size_t StringLength; + size_t TempSize = 2; if (network_info->DomainName[0]) { - size_t StringLength; - size_t TempSize = 2; StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength); TempSize += StringLength; StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength); @@ -497,10 +514,10 @@ } while (!Found && ReadFile(HostsFile, - HostsDBData + ValidData, - sizeof(HostsDBData) - ValidData, - &ReadSize, - NULL)) + HostsDBData + ValidData, + sizeof(HostsDBData) - ValidData, + &ReadSize, + NULL)) { ValidData += ReadSize; ReadSize = 0; @@ -589,38 +606,185 @@ return Address; } -DNS_STATUS WINAPI -DnsQuery_W(LPCWSTR Name, - WORD Type, - DWORD Options, - PIP4_ARRAY Servers, - PDNS_RECORD *QueryResultSet, - PVOID *Reserved) +#define CNAME_LOOP_MAX 16 + +DNS_STATUS +ADNS_Resolve(PVOID hHeap, + LPCWSTR Name, + PCHAR AnsiName, + PFIXED_INFO NetworkInfo, + BOOL DontRecurse, + PDNS_RECORD *QueryResultSet) { adns_state astate; - int quflags = (Options & DNS_QUERY_NO_RECURSION) == 0 ? adns_qf_search : 0; - int adns_error; + adns_query qu; adns_answer *answer; + INT adns_error, quflags = 0; + UINT CNameLoop; LPSTR CurrentName; - unsigned i, CNameLoop; - PFIXED_INFO network_info; - ULONG network_info_blen = 0; - DWORD network_info_result; + PDNS_RECORDW DnsRecord = NULL, LastRecord = NULL; PIP_ADDR_STRING pip; + DNS_STATUS Status; + struct in_addr addr; + + adns_error = adns_init(&astate, adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn, 0); + if (adns_error != adns_s_ok) + { + DPRINT1("ADNS_Resolve adns_init returned error %d\n", adns_error); + Status = DnsIntTranslateAdnsToDNS_STATUS(adns_error); + goto exit; + } + for (pip = &(NetworkInfo->DnsServerList); pip; pip = pip->Next) + { + addr.s_addr = inet_addr(pip->IpAddress.String); + if ((addr.s_addr != INADDR_ANY) && (addr.s_addr != INADDR_NONE)) + adns_addserver(astate, addr); + } + if (NetworkInfo->DomainName[0]) + { + adns_ccf_search(astate, "LOCALDOMAIN", -1, NetworkInfo->DomainName); + } + + /* + * adns doesn't resolve chained CNAME records (a CNAME which points to + * another CNAME pointing to another... pointing to an A record), according + * to a mailing list thread the authors believe that chained CNAME records + * are invalid and the DNS entries should be fixed. That's a nice academic + * standpoint, but there certainly are chained CNAME records out there, + * even some fairly major ones (at the time of this writing + * download.mozilla.org is a chained CNAME). Everyone else seems to resolve + * these fine, so we should too. So we loop here to try to resolve CNAME + * chains ourselves. Of course, there must be a limit to protect against + * CNAME loops. + */ + CurrentName = AnsiName; + for (CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++) + { + DPRINT("ADNS_Resolve Looking up [%d] via adns %s\n", CNameLoop, CurrentName); + adns_error = adns_submit(astate, CurrentName, adns_r_addr, quflags, 0, &qu); + if (adns_error) + { + DPRINT1("ADNS_Resolve adns_submit returned error %d\n", adns_error); + Status = DnsIntTranslateAdnsToDNS_STATUS(adns_error); + goto exit; + } + /* FIXME We should return cancel handle if provided */ + adns_error = adns_wait(astate, &qu, &answer, 0); + if (adns_error != adns_s_ok) + { + DPRINT1("ADNS_Resolve adns_wait returned error %d\n", adns_error); + Status = DnsIntTranslateAdnsToDNS_STATUS(adns_error); + adns_cancel(qu); + goto exit; + } + + if (answer && answer->rrs.addr) + { + DnsRecord = RtlAllocateHeap(hHeap, 0, sizeof(DNS_RECORDW)); + if (!DnsRecord) + { + DPRINT1("ADNS_Resolve could not allocate %d for DnsRecord\n", sizeof(DNS_RECORDW)); + Status = ERROR_OUTOFMEMORY; + goto exit; + } + + if (LastRecord) LastRecord->pNext = DnsRecord; + DnsRecord->pNext = NULL; + DnsRecord->wType = DNS_TYPE_A; + DnsRecord->dwTtl = answer->expires; + DnsRecord->wDataLength = sizeof(DNS_A_DATA); + DnsRecord->Data.A.IpAddress = answer->rrs.addr->addr.inet.sin_addr.s_addr; + DnsRecord->pName = xstrsave(Name); + LastRecord = DnsRecord; + if (!*QueryResultSet) + { + *QueryResultSet = (PDNS_RECORD)DnsRecord; + } + Status = DnsIntTranslateAdnsToDNS_STATUS(adns_error); + goto exit; + } + + if (!answer || answer->status != adns_s_prohibitedcname || !answer->cname/* || DontRecurse*/) + { + DPRINT1("ADNS_Resolve not found %p %d %s %d\n", answer, answer ? answer->status : -1, answer ? answer->cname : NULL, DontRecurse); + /* No answer, answer doesn't have a name or this is an alias and we are requested to search one level only */ + Status = ERROR_FILE_NOT_FOUND; + goto exit; + } + + if (CurrentName != AnsiName) + { + /* This is an alias. Create record for it and link it to last record */ + DnsRecord = RtlAllocateHeap(hHeap, 0, sizeof(DNS_RECORDW)); + if (!DnsRecord) + { + DPRINT1("ADNS_Resolve could not allocate %d for DnsRecord\n", sizeof(DNS_RECORDW)); + Status = ERROR_OUTOFMEMORY; + goto exit; + } + + if (LastRecord) LastRecord->pNext = DnsRecord; + DnsRecord->pNext = NULL; + DnsRecord->wType = DNS_TYPE_CNAME; + DnsRecord->dwTtl = answer->expires; + DnsRecord->wDataLength = sizeof(DNS_PTR_DATAW); + DnsRecord->pName = xstrsave(Name); + DnsRecord->Data.Cname.pNameHost = DnsCToW(answer->cname); + LastRecord = DnsRecord; + if (!*QueryResultSet) + { + /* This is the first record, so attach it to the result */ + *QueryResultSet = (PDNS_RECORD)DnsRecord; + } + RtlFreeHeap(hHeap, 0, CurrentName); + } + + CurrentName = xstrsaveA(answer->cname); + if (!CurrentName) + { + DPRINT1("ADNS_Resolve couldn't copy %p\n", answer->cname); + Status = ERROR_OUTOFMEMORY; + goto exit; + } + } + +exit: + adns_finish(astate); + if (CurrentName && CurrentName != AnsiName) RtlFreeHeap(hHeap, 0, CurrentName); + DPRINT("ADNS_Resolve return %lx\n", Status); + return Status; +} + +DNS_STATUS +ResolverQuery(LPCWSTR Name, + WORD Type, + DWORD Options, + PDNS_RECORD *QueryResultSet, + PDNS_QUERY_COMPLETION_ROUTINE Completion, + PVOID CompletionContext, + PDNS_QUERY_CANCEL Cancel) +{ + PFIXED_INFO NetworkInfo = NULL; + ULONG NetworkInfoLen = 0; IP4_ADDRESS Address; - struct in_addr addr; - PCHAR HostWithDomainName; - PCHAR AnsiName; + PCHAR HostWithDomainName = NULL; + PCHAR AnsiName = NULL; size_t NameLen = 0; + UINT i; + DNS_STATUS Status; + PVOID hHeap; + DNS_QUERY_RESULT QueryResults; + size_t TempLen = 2, StringLength = 0; - if (Name == NULL) - return ERROR_INVALID_PARAMETER; - if (QueryResultSet == NULL) - return ERROR_INVALID_PARAMETER; - if ((Options & DNS_QUERY_WIRE_ONLY) != 0 && (Options & DNS_QUERY_NO_WIRE_QUERY) != 0) - return ERROR_INVALID_PARAMETER; + if (Name == NULL || QueryResultSet == NULL || ((Options & DNS_QUERY_WIRE_ONLY) != 0 && (Options & DNS_QUERY_NO_WIRE_QUERY) != 0)) + { + DPRINT1("ResolverQuery invalid parameter %p %p %lx\n", Name, QueryResultSet, Options); + Status = ERROR_INVALID_PARAMETER; + goto exit; + } - *QueryResultSet = 0; + *QueryResultSet = NULL; + hHeap = RtlGetProcessHeap(); switch (Type) { @@ -634,10 +798,12 @@ 0, NULL, 0); - AnsiName = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen); - if (NULL == AnsiName) + AnsiName = RtlAllocateHeap(hHeap, 0, NameLen); + if (!AnsiName) { - return ERROR_OUTOFMEMORY; + DPRINT1("ResolverQuery could not allocate %d for AnsiName\n", NameLen); + Status = ERROR_OUTOFMEMORY; + goto exit; } WideCharToMultiByte(CP_ACP, 0, @@ -651,12 +817,13 @@ /* Is it an IPv4 address? */ if (ParseV4Address(AnsiName, &Address)) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); - - if (NULL == *QueryResultSet) + DPRINT("ResolverQuery name is an IP %s %lx\n", AnsiName, Address); + *QueryResultSet = RtlAllocateHeap(hHeap, 0, sizeof(DNS_RECORDW)); + if (!*QueryResultSet) { - return ERROR_OUTOFMEMORY; + DPRINT1("ResolverQuery could not allocate %d for DNS_RECORD\n", sizeof(DNS_RECORDW)); + Status = ERROR_OUTOFMEMORY; + goto exit; } (*QueryResultSet)->pNext = NULL; @@ -663,10 +830,10 @@ (*QueryResultSet)->wType = Type; (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA); (*QueryResultSet)->Data.A.IpAddress = Address; - (*QueryResultSet)->pName = (LPSTR)xstrsave(Name); - return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; + Status = (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; + goto exit; } /* Check allowed characters @@ -675,8 +842,9 @@ if (AnsiName[0] == '-' || AnsiName[0] == '_' || AnsiName[NameLen - 1] == '-' || AnsiName[NameLen - 1] == '_' || strstr(AnsiName, "..") != NULL) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - return ERROR_INVALID_NAME; + DPRINT1("ResolverQuery invalid name %s\n", AnsiName); + Status = ERROR_INVALID_NAME; + goto exit; } i = 0; while (i < NameLen) @@ -686,8 +854,9 @@ (AnsiName[i] >= '0' && AnsiName[i] <= '9') || AnsiName[i] == '-' || AnsiName[i] == '_' || AnsiName[i] == '.')) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - return ERROR_INVALID_NAME; + DPRINT1("ResolverQuery invalid character found in name %s %d %c\n", AnsiName, i, AnsiName[i]); + Status = ERROR_INVALID_NAME; + goto exit; } i++; } @@ -694,14 +863,16 @@ if ((Options & DNS_QUERY_NO_HOSTS_FILE) == 0) { + /* FIXME FindEntryInHosts should return aliases also */ if ((Address = FindEntryInHosts(AnsiName)) != 0) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); - - if (NULL == *QueryResultSet) + DPRINT("ResolverQuery host %s found in hosts %lx\n", AnsiName, Address); + *QueryResultSet = RtlAllocateHeap(hHeap, 0, sizeof(DNS_RECORDW)); + if (!*QueryResultSet) { - return ERROR_OUTOFMEMORY; + DPRINT1("ResolverQuery could not allocate %d for DNS_RECORD\n", sizeof(DNS_RECORDW)); + Status = ERROR_OUTOFMEMORY; + goto exit; } (*QueryResultSet)->pNext = NULL; @@ -708,49 +879,59 @@ (*QueryResultSet)->wType = Type; (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA); (*QueryResultSet)->Data.A.IpAddress = Address; - (*QueryResultSet)->pName = (LPSTR)xstrsave(Name); - return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; + Status = (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; + goto exit; } } - network_info_result = GetNetworkParams(NULL, &network_info_blen); - network_info = (PFIXED_INFO)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen); - if (NULL == network_info) + GetNetworkParams(NULL, &NetworkInfoLen); + NetworkInfo = (PFIXED_INFO)RtlAllocateHeap(hHeap, 0, (size_t)NetworkInfoLen); + if (!NetworkInfo) { - return ERROR_OUTOFMEMORY; + DPRINT1("ResolverQuery could not allocate %ld for NetworkInfo\n", NetworkInfoLen); + Status = ERROR_OUTOFMEMORY; + goto exit; } - network_info_result = GetNetworkParams(network_info, &network_info_blen); - if (network_info_result != ERROR_SUCCESS) + Status = GetNetworkParams(NetworkInfo, &NetworkInfoLen); + if (Status != ERROR_SUCCESS) { - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); - return network_info_result; + DPRINT1("ResolverQuery GetNetworkParams returned %lx\n", Address); + goto exit; } - if ((Address = CheckForCurrentHostname(NameLen != 0 ? AnsiName : network_info->HostName, network_info)) != 0) + if ((Address = CheckForCurrentHostname(NameLen != 0 ? AnsiName : NetworkInfo->HostName, NetworkInfo)) != 0) { - size_t TempLen = 2, StringLength = 0; - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength); + DPRINT("ResolverQuery CheckForCurrentHostname returned %lx\n", Address); + + StringCchLengthA(NetworkInfo->HostName, sizeof(NetworkInfo->HostName), &StringLength); TempLen += StringLength; - StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength); + StringCchLengthA(NetworkInfo->DomainName, sizeof(NetworkInfo->DomainName), &StringLength); TempLen += StringLength; - HostWithDomainName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen); - StringCchCopyA(HostWithDomainName, TempLen, network_info->HostName); - if (network_info->DomainName[0]) + + HostWithDomainName = (PCHAR)RtlAllocateHeap(hHeap, 0, TempLen); + if (!HostWithDomainName) { + DPRINT1("ResolverQuery could not allocate %ld for HostWithDomainName\n", TempLen); + Status = ERROR_OUTOFMEMORY; + goto exit; + } + + StringCchCopyA(HostWithDomainName, TempLen, NetworkInfo->HostName); + if (NetworkInfo->DomainName[0]) + { StringCchCatA(HostWithDomainName, TempLen, "."); - StringCchCatA(HostWithDomainName, TempLen, network_info->DomainName); + StringCchCatA(HostWithDomainName, TempLen, NetworkInfo->DomainName); } - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); - *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); + *QueryResultSet = RtlAllocateHeap(hHeap, 0, sizeof(DNS_RECORDW)); - if (NULL == *QueryResultSet) + if (!*QueryResultSet) { - RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName); - return ERROR_OUTOFMEMORY; + DPRINT1("ResolverQuery could not allocate %d for DNS_RECORD\n", sizeof(DNS_RECORDW)); + Status = ERROR_OUTOFMEMORY; + goto exit; } (*QueryResultSet)->pNext = NULL; @@ -757,137 +938,136 @@ (*QueryResultSet)->wType = Type; (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA); (*QueryResultSet)->Data.A.IpAddress = Address; - (*QueryResultSet)->pName = (LPSTR)DnsCToW(HostWithDomainName); - RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName); - return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; + Status = (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; + goto exit; } if ((Options & DNS_QUERY_NO_WIRE_QUERY) != 0) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); - return ERROR_FILE_NOT_FOUND; + DPRINT("ResolverQuery no wire query flag is set\n"); + Status = ERROR_FILE_NOT_FOUND; + goto exit; } - adns_error = adns_init(&astate, adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn, 0); - if (adns_error != adns_s_ok) - { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); - return DnsIntTranslateAdnsToDNS_STATUS(adns_error); - } - for (pip = &(network_info->DnsServerList); pip; pip = pip->Next) - { - addr.s_addr = inet_addr(pip->IpAddress.String); - if ((addr.s_addr != INADDR_ANY) && (addr.s_addr != INADDR_NONE)) - adns_addserver(astate, addr); - } - if (network_info->DomainName[0]) - { - adns_ccf_search(astate, "LOCALDOMAIN", -1, network_info->DomainName); - } - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); + // FIXME Handle async + Status = ADNS_Resolve(hHeap, + Name, + AnsiName, + NetworkInfo, + (Options & DNS_QUERY_NO_RECURSION) != 0, + QueryResultSet); + break; - if (Servers) - { - for (i = 0; i < Servers->AddrCount; i++) - { - adns_addserver(astate, *((struct in_addr *)&Servers->AddrArray[i])); - } - } + default: + DPRINT1("ResolverQuery unsupported query %d\n", Type); + Status = ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */ + break; + } - /* - * adns doesn't resolve chained CNAME records (a CNAME which points to - * another CNAME pointing to another... pointing to an A record), according - * to a mailing list thread the authors believe that chained CNAME records - * are invalid and the DNS entries should be fixed. That's a nice academic - * standpoint, but there certainly are chained CNAME records out there, - * even some fairly major ones (at the time of this writing - * download.mozilla.org is a chained CNAME). Everyone else seems to resolve - * these fine, so we should too. So we loop here to try to resolve CNAME - * chains ourselves. Of course, there must be a limit to protect against - * CNAME loops. - */ +exit: + if (AnsiName) RtlFreeHeap(hHeap, 0, AnsiName); + if (NetworkInfo) RtlFreeHeap(hHeap, 0, NetworkInfo); + if (HostWithDomainName) RtlFreeHeap(hHeap, 0, HostWithDomainName); + if (Completion) + { + DPRINT("ResolverQuery Completion %p\n", Completion); + QueryResults.Version = DNS_QUERY_REQUEST_VERSION1; + QueryResults.QueryOptions = Options; + QueryResults.QueryStatus = Status; + QueryResults.pQueryRecords = *QueryResultSet; + QueryResults.Reserved = NULL; + Completion(CompletionContext, &QueryResults); + } + DPRINT("ResolverQuery return %lx\n", Status); + return Status; +} -#define CNAME_LOOP_MAX 16 +DNS_STATUS WINAPI +DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest, + PDNS_QUERY_RESULT pQueryResults, + PDNS_QUERY_CANCEL pCancelHandle) +{ + DPRINT("DnsQueryEx %p %p %p\n", pQueryRequest, pQueryResults, pCancelHandle); + if (!pQueryRequest || !pQueryResults) + return ERROR_INVALID_PARAMETER; - CurrentName = AnsiName; + pQueryResults->QueryStatus = ResolverQuery(pQueryRequest->QueryName, + pQueryRequest->QueryType, + pQueryRequest->QueryOptions, + &pQueryResults->pQueryRecords, + pQueryRequest->pQueryCompletionCallback, + pQueryRequest->pQueryContext, + pCancelHandle); + DPRINT("DnsQueryEx ret %ld\n", pQueryResults->QueryStatus); + return pQueryResults->QueryStatus; +} - for (CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++) - { - adns_error = adns_synchronous(astate, CurrentName, adns_r_addr, quflags, &answer); +DNS_STATUS +WINAPI +DnsCancelQuery(PDNS_QUERY_CANCEL pCancelHandle) +{ + UNIMPLEMENTED; + return ERROR_OUTOFMEMORY; +} - if (adns_error != adns_s_ok) - { - adns_finish(astate); +DNS_STATUS WINAPI +DnsQuery_W(LPCWSTR Name, + WORD Type, + DWORD Options, + PVOID pExtra, + PDNS_RECORD *QueryResultSet, + PVOID *Reserved) +{ + DNS_STATUS Status; + DWORD dwResCount = 0; + WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH]; + DWORD dwComputerNameSize = _countof(wszComputerName); + PDNS_RECORDW CacheResultSet = NULL; + DNS_QUERY_REQUEST QueryRequest = { 0 }; + DNS_QUERY_RESULT QueryResults = { 0 }; - if (CurrentName != AnsiName) - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); - - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - return DnsIntTranslateAdnsToDNS_STATUS(adns_error); - } - - if (answer && answer->rrs.addr) + DPRINT("DnsQuery_W\n"); + if ((Options & DNS_QUERY_BYPASS_CACHE) == 0) + { + /* FIXME Use DnsGetHostName_W when available */ + RpcTryExcept + { + GetComputerNameW(wszComputerName, &dwComputerNameSize); + Status = R_ResolverQuery(wszComputerName, Name, Type, Options, &dwResCount, &CacheResultSet); + DPRINT("DnsQuery_W query cache status %lx %ld\n", Status, dwResCount); + if (Status == STATUS_SUCCESS) { - if (CurrentName != AnsiName) - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); - - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); - - if (NULL == *QueryResultSet) - { - adns_finish(astate); - return ERROR_OUTOFMEMORY; - } - - (*QueryResultSet)->pNext = NULL; - (*QueryResultSet)->wType = Type; - (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA); - (*QueryResultSet)->Data.A.IpAddress = answer->rrs.addr->addr.inet.sin_addr.s_addr; - - adns_finish(astate); - - (*QueryResultSet)->pName = (LPSTR)xstrsave(Name); - - return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; + *QueryResultSet = DnsRecordSetCopyEx((PDNS_RECORD)CacheResultSet, DnsCharSetUnicode, DnsCharSetUnicode); + DnsRecordListFree((PDNS_RECORD)CacheResultSet, DnsFreeRecordList); } - - if (NULL == answer || adns_s_prohibitedcname != answer->status || NULL == answer->cname) - { - adns_finish(astate); - - if (CurrentName != AnsiName) - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); - - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - return ERROR_FILE_NOT_FOUND; - } - - if (CurrentName != AnsiName) - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); - - CurrentName = (LPSTR)xstrsaveA(answer->cname); - - if (!CurrentName) - { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - adns_finish(astate); - return ERROR_OUTOFMEMORY; - } + return Status; } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + Status = RpcExceptionCode(); + DPRINT("DnsQuery_W query cache error %lx. Will try direct query\n", Status); + } + RpcEndExcept; + } + else + { + DPRINT("DnsQuery_W bypassing cache\n"); + } - adns_finish(astate); - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); - return ERROR_FILE_NOT_FOUND; - - default: - return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */ - } + QueryRequest.Version = DNS_QUERY_REQUEST_VERSION1; + QueryRequest.QueryType = Type; + QueryRequest.QueryName = Name; + QueryRequest.QueryOptions = Options; + QueryResults.Version = DNS_QUERY_REQUEST_VERSION1; + Status = DnsQueryEx(&QueryRequest, + &QueryResults, + NULL /* we want this query synchronous */); + *QueryResultSet = DnsRecordSetCopyEx(QueryResults.pQueryRecords, DnsCharSetUnicode, DnsCharSetUnicode); + DnsRecordListFree((PDNS_RECORD)QueryResults.pQueryRecords, DnsFreeRecordList); + DPRINT("DnsQuery_W DnsQueryEx result %ld\n", Status); + return Status; } DNS_STATUS WINAPI @@ -894,7 +1074,7 @@ DnsQuery_UTF8(LPCSTR Name, WORD Type, DWORD Options, - PIP4_ARRAY Servers, + PVOID pExtra, PDNS_RECORD *QueryResultSet, PVOID *Reserved) { @@ -944,3 +1124,26 @@ ToDelete = next; } } + +DNS_STATUS WINAPI +DnsFlushResolverCache() +{ + DNS_STATUS Status; + WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH]; + DWORD dwComputerNameSize = _countof(wszComputerName); + + DPRINT("DnsFlushResolverCache\n"); + /* FIXME Use DnsGetHostName_W when available */ + GetComputerNameW(wszComputerName, &dwComputerNameSize); + RpcTryExcept + { + Status = R_ResolverFlushCache(wszComputerName); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + Status = RpcExceptionCode(); + } + RpcEndExcept; + DPRINT("DnsFlushResolverCache status %lx\n", Status); + return Status; +} Index: dll/win32/dnsapi/dnsapi/rpc.c =================================================================== --- dll/win32/dnsapi/dnsapi/rpc.c (revision 0) +++ dll/win32/dnsapi/dnsapi/rpc.c (working copy) @@ -0,0 +1,75 @@ +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H +#include +#include +#include +#include + +#define NDEBUG +#include + +handle_t __RPC_USER +DNSRSLVR_HANDLE_bind(DNSRSLVR_HANDLE szMachineName) +{ + handle_t hBinding = NULL; + LPWSTR pszStringBinding; + RPC_STATUS Status; + + DPRINT("RPC_SERVICE_STATUS_HANDLE_bind() called\n"); + + Status = RpcStringBindingComposeW(NULL, + L"ncalrpc", + szMachineName, + L"DNSResolver", + NULL, + &pszStringBinding); + if (Status != RPC_S_OK) + { + DPRINT1("RpcStringBindingCompose returned 0x%x\n", Status); + return NULL; + } + + /* Set the binding handle that will be used to bind to the server. */ + Status = RpcBindingFromStringBindingW(pszStringBinding, + &hBinding); + if (Status != RPC_S_OK) + { + DPRINT1("RpcBindingFromStringBinding returned 0x%x\n", Status); + } + + Status = RpcStringFreeW(&pszStringBinding); + if (Status != RPC_S_OK) + { + DPRINT1("RpcStringFree returned 0x%x\n", Status); + } + + return hBinding; +} + +void __RPC_USER +DNSRSLVR_HANDLE_unbind(DNSRSLVR_HANDLE szMachineName, + handle_t hBinding) +{ + RPC_STATUS Status; + + DPRINT("DNSRSLVR_HANDLE() called\n"); + + Status = RpcBindingFree(&hBinding); + if (Status != RPC_S_OK) + { + DPRINT1("RpcBindingFree returned 0x%x\n", 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); +} Index: dll/win32/dnsapi/dnsapi/stubs.c =================================================================== --- dll/win32/dnsapi/dnsapi/stubs.c (revision 74743) +++ dll/win32/dnsapi/dnsapi/stubs.c (working copy) @@ -216,13 +216,6 @@ return ERROR_OUTOFMEMORY; } -DNS_STATUS WINAPI -DnsFlushResolverCache() -{ - UNIMPLEMENTED; - return ERROR_OUTOFMEMORY; -} - BOOL WINAPI DnsFlushResolverCacheEntry_A(PCSTR entry) { @@ -539,13 +532,6 @@ } DNS_STATUS WINAPI -DnsQueryEx() -{ - UNIMPLEMENTED; - return ERROR_OUTOFMEMORY; -} - -DNS_STATUS WINAPI DnsRecordBuild_UTF8() { UNIMPLEMENTED; @@ -813,13 +799,6 @@ } DNS_STATUS WINAPI -GetCurrentTimeInSeconds() -{ - UNIMPLEMENTED; - return ERROR_OUTOFMEMORY; -} - -DNS_STATUS WINAPI DnsNotifyResolver() { UNIMPLEMENTED; Index: dll/win32/dnsapi/include/internal/windns.h =================================================================== --- dll/win32/dnsapi/include/internal/windns.h (revision 74743) +++ dll/win32/dnsapi/include/internal/windns.h (working copy) @@ -11,4 +11,14 @@ DNS_STATUS DnsIntTranslateAdnsToDNS_STATUS(int Status); void DnsIntFreeRecordList(PDNS_RECORD ToFree); +typedef LPWSTR DNSRSLVR_HANDLE; +DWORD __cdecl R_ResolverFlushCache(DNSRSLVR_HANDLE pwszServerName); + +DWORD __cdecl R_ResolverQuery(DNSRSLVR_HANDLE pwszServerName, + LPCWSTR pwsName, + WORD wType, + DWORD Flags, + DWORD *dwRecords, + DNS_RECORDW **ppResultRecords); + #endif /* WINDNS_INTERNAL_H */ Index: media/inf/nettcpip.inf =================================================================== --- media/inf/nettcpip.inf (revision 74743) +++ media/inf/nettcpip.inf (working copy) @@ -235,6 +235,7 @@ [MS_TCPIP.PrimaryInstall.Services] AddService = Tcpip, , tcpip_Service_Inst AddService = DHCP, , dhcp_Service_Inst +AddService = Dnscache, , dns_Service_Inst [tcpip_Service_Inst] ServiceType = 1 @@ -269,6 +270,20 @@ 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] Index: sdk/include/psdk/windns.h =================================================================== --- sdk/include/psdk/windns.h (revision 74743) +++ sdk/include/psdk/windns.h (working copy) @@ -667,6 +667,10 @@ DNS_STATUS WINAPI +DnsFlushResolverCache(); + +DNS_STATUS +WINAPI DnsAcquireContextHandle_A( _In_ DWORD CredentialFlags, _In_opt_ PVOID Credentials, @@ -741,7 +745,7 @@ _In_ PCSTR pszName, _In_ WORD wType, _In_ DWORD Options, - _Inout_opt_ PIP4_ARRAY pExtra, + _Inout_opt_ PVOID pExtra, _Outptr_result_maybenull_ PDNS_RECORD *ppQueryResults, _Outptr_opt_result_maybenull_ PVOID *pReserved); @@ -751,7 +755,7 @@ _In_ PCWSTR pszName, _In_ WORD wType, _In_ DWORD Options, - _Inout_opt_ PIP4_ARRAY pExtra, + _Inout_opt_ PVOID pExtra, _Outptr_result_maybenull_ PDNS_RECORD *ppQueryResults, _Outptr_opt_result_maybenull_ PVOID *pReserved); @@ -761,7 +765,7 @@ _In_ PCSTR pszName, _In_ WORD wType, _In_ DWORD Options, - _Inout_opt_ PIP4_ARRAY pExtra, + _Inout_opt_ PVOID pExtra, _Outptr_result_maybenull_ PDNS_RECORD *ppQueryResults, _Outptr_opt_result_maybenull_ PVOID *pReserved); @@ -883,6 +887,63 @@ _In_ WORD wType, _In_ WORD Xid, _In_ BOOL fRecursionDesired); + +#define DNS_QUERY_RESULTS_VERSION1 0x1 + +typedef struct _DNS_QUERY_RESULT +{ + _In_ ULONG Version; + _Out_ DNS_STATUS QueryStatus; + _Out_ ULONG64 QueryOptions; + _Out_ PDNS_RECORD pQueryRecords; + _Inout_opt_ PVOID Reserved; +} +DNS_QUERY_RESULT, *PDNS_QUERY_RESULT; + +typedef +VOID +WINAPI +DNS_QUERY_COMPLETION_ROUTINE( + _In_ PVOID pQueryContext, + _Inout_ PDNS_QUERY_RESULT pQueryResults +); + +typedef DNS_QUERY_COMPLETION_ROUTINE *PDNS_QUERY_COMPLETION_ROUTINE; + +#define DNS_QUERY_REQUEST_VERSION1 0x1 + +typedef struct _DNS_QUERY_REQUEST +{ + _In_ ULONG Version; + _In_opt_ PCWSTR QueryName; + _In_ WORD QueryType; + _In_ ULONG64 QueryOptions; + _In_opt_ PDNS_ADDR_ARRAY pDnsServerList; + _In_opt_ ULONG InterfaceIndex; + _In_opt_ PDNS_QUERY_COMPLETION_ROUTINE pQueryCompletionCallback; + _In_ PVOID pQueryContext; +} +DNS_QUERY_REQUEST, *PDNS_QUERY_REQUEST; + +typedef struct _DNS_QUERY_CANCEL +{ + CHAR Reserved[32]; +} +DNS_QUERY_CANCEL, *PDNS_QUERY_CANCEL; + +DNS_STATUS +WINAPI +DnsQueryEx( + _In_ PDNS_QUERY_REQUEST pQueryRequest, + _Inout_ PDNS_QUERY_RESULT pQueryResults, + _Inout_opt_ PDNS_QUERY_CANCEL pCancelHandle +); + +DNS_STATUS +WINAPI +DnsCancelQuery( + _In_ PDNS_QUERY_CANCEL pCancelHandle +); #endif #ifdef UNICODE