reactos/dll/win32/dnsapi/query.c

1005 lines
31 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/dnsapi/dnsapi/query.c
* PURPOSE: DNSAPI functions built on the ADNS library.
* PROGRAMER: Art Yerkes
* UPDATE HISTORY:
* 12/15/03 -- Created
*/
#include "precomp.h"
#include <winreg.h>
#include <iphlpapi.h>
#include <strsafe.h>
#define NDEBUG
#include <debug.h>
static
BOOL
ParseIpv4Address(
_In_ PCWSTR AddressString,
_Out_ PIN_ADDR pAddress)
{
PCWSTR pTerminator = NULL;
NTSTATUS Status;
Status = RtlIpv4StringToAddressW(AddressString,
TRUE,
&pTerminator,
pAddress);
if (NT_SUCCESS(Status) && pTerminator != NULL && *pTerminator == L'\0')
return TRUE;
return FALSE;
}
static
BOOL
ParseIpv6Address(
_In_ PCWSTR AddressString,
_Out_ PIN6_ADDR pAddress)
{
PCWSTR pTerminator = NULL;
NTSTATUS Status;
Status = RtlIpv6StringToAddressW(AddressString,
&pTerminator,
pAddress);
if (NT_SUCCESS(Status) && pTerminator != NULL && *pTerminator == L'\0')
return TRUE;
return FALSE;
}
static
PDNS_RECORDW
CreateRecordForIpAddress(
_In_ PCWSTR Name,
_In_ WORD Type)
{
IN_ADDR Ip4Address;
IN6_ADDR Ip6Address;
PDNS_RECORDW pRecord = NULL;
if (Type == DNS_TYPE_A)
{
if (ParseIpv4Address(Name, &Ip4Address))
{
pRecord = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(DNS_RECORDW));
if (pRecord == NULL)
return NULL;
pRecord->pName = RtlAllocateHeap(RtlGetProcessHeap(),
0,
(wcslen(Name) + 1) * sizeof(WCHAR));
if (pRecord == NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, pRecord);
return NULL;
}
wcscpy(pRecord->pName, Name);
pRecord->wType = DNS_TYPE_A;
pRecord->wDataLength = sizeof(DNS_A_DATA);
pRecord->Flags.S.Section = DnsSectionQuestion;
pRecord->Flags.S.CharSet = DnsCharSetUnicode;
pRecord->dwTtl = 7 * 24 * 60 * 60;
pRecord->Data.A.IpAddress = Ip4Address.S_un.S_addr;
return pRecord;
}
}
else if (Type == DNS_TYPE_AAAA)
{
if (ParseIpv6Address(Name, &Ip6Address))
{
pRecord = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(DNS_RECORDW));
if (pRecord == NULL)
return NULL;
pRecord->pName = RtlAllocateHeap(RtlGetProcessHeap(),
0,
(wcslen(Name) + 1) * sizeof(WCHAR));
if (pRecord == NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, pRecord);
return NULL;
}
wcscpy(pRecord->pName, Name);
pRecord->wType = DNS_TYPE_AAAA;
pRecord->wDataLength = sizeof(DNS_AAAA_DATA);
pRecord->Flags.S.Section = DnsSectionQuestion;
pRecord->Flags.S.CharSet = DnsCharSetUnicode;
pRecord->dwTtl = 7 * 24 * 60 * 60;
CopyMemory(&pRecord->Data.AAAA.Ip6Address,
&Ip6Address.u.Byte,
sizeof(IN6_ADDR));
return pRecord;
}
}
return NULL;
}
/* 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
* functions.
*
* Name -- The DNS object to be queried.
* Type -- The type of records to be returned. These are
* listed in windns.h
* Options -- Query options. DNS_QUERY_STANDARD is the base
* state, and every other option takes precedence.
* multiple options can be combined. Listed in
* windns.h
* Servers -- List of alternate servers (optional)
* QueryResultSet -- Pointer to the result pointer that will be filled
* when the response is available.
* Reserved -- Response as it appears on the wire. Optional.
*/
static PCHAR
DnsWToC(const WCHAR *WideString)
{
PCHAR AnsiString;
int AnsiLen = WideCharToMultiByte(CP_ACP,
0,
WideString,
-1,
NULL,
0,
NULL,
0);
if (AnsiLen == 0)
return NULL;
AnsiString = RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen);
if (AnsiString == NULL)
{
return NULL;
}
WideCharToMultiByte(CP_ACP,
0,
WideString,
-1,
AnsiString,
AnsiLen,
NULL,
0);
return AnsiString;
}
static PWCHAR
DnsCToW(const CHAR *NarrowString)
{
PWCHAR WideString;
int WideLen = MultiByteToWideChar(CP_ACP,
0,
NarrowString,
-1,
NULL,
0);
if (WideLen == 0)
return NULL;
WideString = RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen * sizeof(WCHAR));
if (WideString == NULL)
{
return NULL;
}
MultiByteToWideChar(CP_ACP,
0,
NarrowString,
-1,
WideString,
WideLen);
return WideString;
}
static PCHAR
DnsWToUTF8(const WCHAR *WideString)
{
PCHAR AnsiString;
int AnsiLen = WideCharToMultiByte(CP_UTF8,
0,
WideString,
-1,
NULL,
0,
NULL,
0);
if (AnsiLen == 0)
return NULL;
AnsiString = RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen);
if (AnsiString == NULL)
{
return NULL;
}
WideCharToMultiByte(CP_UTF8,
0,
WideString,
-1,
AnsiString,
AnsiLen,
NULL,
0);
return AnsiString;
}
static PWCHAR
DnsUTF8ToW(const CHAR *NarrowString)
{
PWCHAR WideString;
int WideLen = MultiByteToWideChar(CP_UTF8,
0,
NarrowString,
-1,
NULL,
0);
if (WideLen == 0)
return NULL;
WideString = RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen * sizeof(WCHAR));
if (WideString == NULL)
{
return NULL;
}
MultiByteToWideChar(CP_UTF8,
0,
NarrowString,
-1,
WideString,
WideLen);
return WideString;
}
DNS_STATUS WINAPI
DnsQuery_CodePage(UINT CodePage,
LPCSTR Name,
WORD Type,
DWORD Options,
PVOID Extra,
PDNS_RECORD *QueryResultSet,
PVOID *Reserved)
{
UINT i;
PWCHAR Buffer;
DNS_STATUS Status;
PDNS_RECORD QueryResultWide;
PDNS_RECORD ConvertedRecord = 0, LastRecord = 0;
if (Name == NULL)
return ERROR_INVALID_PARAMETER;
if (QueryResultSet == NULL)
return ERROR_INVALID_PARAMETER;
switch (CodePage)
{
case CP_ACP:
Buffer = DnsCToW(Name);
break;
case CP_UTF8:
Buffer = DnsUTF8ToW(Name);
break;
default:
return ERROR_INVALID_PARAMETER;
}
Status = DnsQuery_W(Buffer, Type, Options, Extra, &QueryResultWide, Reserved);
while (Status == ERROR_SUCCESS && QueryResultWide)
{
switch (QueryResultWide->wType)
{
case DNS_TYPE_A:
case DNS_TYPE_WKS:
case DNS_TYPE_CNAME:
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_MB:
case DNS_TYPE_MD:
case DNS_TYPE_MF:
case DNS_TYPE_MG:
case DNS_TYPE_MR:
ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
break;
case DNS_TYPE_MINFO:
ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATA) + QueryResultWide->Data.TXT.dwStringCount);
break;
case DNS_TYPE_NULL:
ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount);
break;
}
if (ConvertedRecord == NULL)
{
/* The name */
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
/* The result*/
DnsIntFreeRecordList(QueryResultWide);
QueryResultSet = NULL;
return ERROR_OUTOFMEMORY;
}
if (CodePage == CP_ACP)
{
ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName);
ConvertedRecord->Flags.S.CharSet = DnsCharSetAnsi;
}
else
{
ConvertedRecord->pName = DnsWToUTF8((PWCHAR)QueryResultWide->pName);
ConvertedRecord->Flags.S.CharSet = DnsCharSetUtf8;
}
ConvertedRecord->wType = QueryResultWide->wType;
switch (QueryResultWide->wType)
{
case DNS_TYPE_A:
case DNS_TYPE_WKS:
ConvertedRecord->wDataLength = QueryResultWide->wDataLength;
memcpy(&ConvertedRecord->Data, &QueryResultWide->Data, QueryResultWide->wDataLength);
break;
case DNS_TYPE_CNAME:
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_MB:
case DNS_TYPE_MD:
case DNS_TYPE_MF:
case DNS_TYPE_MG:
case DNS_TYPE_MR:
ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATA);
if (CodePage == CP_ACP)
ConvertedRecord->Data.PTR.pNameHost = DnsWToC((PWCHAR)QueryResultWide->Data.PTR.pNameHost);
else
ConvertedRecord->Data.PTR.pNameHost = DnsWToUTF8((PWCHAR)QueryResultWide->Data.PTR.pNameHost);
break;
case DNS_TYPE_MINFO:
ConvertedRecord->wDataLength = sizeof(DNS_MINFO_DATA);
if (CodePage == CP_ACP)
{
ConvertedRecord->Data.MINFO.pNameMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameMailbox);
ConvertedRecord->Data.MINFO.pNameErrorsMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameErrorsMailbox);
}
else
{
ConvertedRecord->Data.MINFO.pNameMailbox = DnsWToUTF8((PWCHAR)QueryResultWide->Data.MINFO.pNameMailbox);
ConvertedRecord->Data.MINFO.pNameErrorsMailbox = DnsWToUTF8((PWCHAR)QueryResultWide->Data.MINFO.pNameErrorsMailbox);
}
break;
case DNS_TYPE_MX:
ConvertedRecord->wDataLength = sizeof(DNS_MX_DATA);
if (CodePage == CP_ACP)
ConvertedRecord->Data.MX.pNameExchange = DnsWToC((PWCHAR)QueryResultWide->Data.MX.pNameExchange);
else
ConvertedRecord->Data.MX.pNameExchange = DnsWToUTF8((PWCHAR)QueryResultWide->Data.MX.pNameExchange);
ConvertedRecord->Data.MX.wPreference = QueryResultWide->Data.MX.wPreference;
break;
case DNS_TYPE_HINFO:
ConvertedRecord->wDataLength = sizeof(DNS_TXT_DATA) + (sizeof(PCHAR) * QueryResultWide->Data.TXT.dwStringCount);
ConvertedRecord->Data.TXT.dwStringCount = QueryResultWide->Data.TXT.dwStringCount;
if (CodePage == CP_ACP)
for (i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++)
ConvertedRecord->Data.TXT.pStringArray[i] = DnsWToC((PWCHAR)QueryResultWide->Data.TXT.pStringArray[i]);
else
for (i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++)
ConvertedRecord->Data.TXT.pStringArray[i] = DnsWToUTF8((PWCHAR)QueryResultWide->Data.TXT.pStringArray[i]);
break;
case DNS_TYPE_NULL:
ConvertedRecord->wDataLength = sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount;
ConvertedRecord->Data.Null.dwByteCount = QueryResultWide->Data.Null.dwByteCount;
memcpy(&ConvertedRecord->Data.Null.Data, &QueryResultWide->Data.Null.Data, QueryResultWide->Data.Null.dwByteCount);
break;
}
if (LastRecord)
{
LastRecord->pNext = ConvertedRecord;
LastRecord = LastRecord->pNext;
}
else
{
LastRecord = *QueryResultSet = ConvertedRecord;
}
QueryResultWide = QueryResultWide->pNext;
}
if (LastRecord)
LastRecord->pNext = 0;
/* The name */
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
/* The result*/
if (QueryResultWide) DnsIntFreeRecordList(QueryResultWide);
return Status;
}
DNS_STATUS WINAPI
DnsQuery_A(LPCSTR Name,
WORD Type,
DWORD Options,
PVOID Extra,
PDNS_RECORD *QueryResultSet,
PVOID *Reserved)
{
return DnsQuery_CodePage(CP_ACP, Name, Type, Options, Extra, QueryResultSet, Reserved);
}
DNS_STATUS WINAPI
DnsQuery_UTF8(LPCSTR Name,
WORD Type,
DWORD Options,
PVOID Extra,
PDNS_RECORD *QueryResultSet,
PVOID *Reserved)
{
return DnsQuery_CodePage(CP_UTF8, Name, Type, Options, Extra, QueryResultSet, Reserved);
}
DNS_STATUS
WINAPI
DnsQuery_W(LPCWSTR Name,
WORD Type,
DWORD Options,
PVOID Extra,
PDNS_RECORD *QueryResultSet,
PVOID *Reserved)
{
DWORD dwRecords = 0;
PDNS_RECORDW pRecord = NULL;
size_t NameLen, i;
DNS_STATUS Status = ERROR_SUCCESS;
DPRINT("DnsQuery_W()\n");
if ((Name == NULL) ||
(QueryResultSet == NULL))
return ERROR_INVALID_PARAMETER;
*QueryResultSet = NULL;
/* Create an A or AAAA record for an IP4 or IP6 address */
pRecord = CreateRecordForIpAddress(Name,
Type);
if (pRecord != NULL)
{
*QueryResultSet = (PDNS_RECORD)pRecord;
return ERROR_SUCCESS;
}
/*
* Check allowed characters
* According to RFC a-z,A-Z,0-9,-,_, but can't start or end with - or _
*/
NameLen = wcslen(Name);
if (Name[0] == L'-' || Name[0] == L'_' || Name[NameLen - 1] == L'-' ||
Name[NameLen - 1] == L'_' || wcsstr(Name, L"..") != NULL)
{
return ERROR_INVALID_NAME;
}
i = 0;
while (i < NameLen)
{
if (!((Name[i] >= L'a' && Name[i] <= L'z') ||
(Name[i] >= L'A' && Name[i] <= L'Z') ||
(Name[i] >= L'0' && Name[i] <= L'9') ||
Name[i] == L'-' || Name[i] == L'_' || Name[i] == L'.'))
{
return DNS_ERROR_INVALID_NAME_CHAR;
}
i++;
}
RpcTryExcept
{
Status = R_ResolverQuery(NULL,
Name,
Type,
Options,
&dwRecords,
(DNS_RECORDW **)QueryResultSet);
DPRINT("R_ResolverQuery() returned %lu\n", Status);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
Status = RpcExceptionCode();
DPRINT("Exception returned %lu\n", Status);
}
RpcEndExcept;
return Status;
}
WCHAR
*xstrsave(const WCHAR *str)
{
WCHAR *p;
size_t len = 0;
/* FIXME: how much instead of MAX_PATH? */
StringCbLengthW(str, MAX_PATH, &len);
len+=sizeof(WCHAR);
p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
if (p)
StringCbCopyW(p, len, str);
return p;
}
CHAR
*xstrsaveA(const CHAR *str)
{
CHAR *p;
size_t len = 0;
/* FIXME: how much instead of MAX_PATH? */
StringCbLengthA(str, MAX_PATH, &len);
len++;
p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
if (p)
StringCbCopyA(p, len, str);
return p;
}
/* This function is far from perfect but it works enough */
IP4_ADDRESS
CheckForCurrentHostname(CONST CHAR * Name, PFIXED_INFO network_info)
{
PCHAR TempName;
DWORD AdapterAddressesSize, Status;
IP4_ADDRESS ret = 0, Address;
PIP_ADAPTER_ADDRESSES Addresses = NULL, pip;
BOOL Found = FALSE;
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);
TempSize += StringLength;
TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, TempSize);
StringCchCopyA(TempName, TempSize, network_info->HostName);
StringCchCatA(TempName, TempSize, ".");
StringCchCatA(TempName, TempSize, network_info->DomainName);
}
else
{
TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, 1);
TempName[0] = 0;
}
Found = !stricmp(Name, network_info->HostName) || !stricmp(Name, TempName);
RtlFreeHeap(RtlGetProcessHeap(), 0, TempName);
if (!Found)
{
return 0;
}
/* get adapter info */
AdapterAddressesSize = 0;
GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
NULL,
Addresses,
&AdapterAddressesSize);
if (!AdapterAddressesSize)
{
return 0;
}
Addresses = RtlAllocateHeap(RtlGetProcessHeap(), 0, AdapterAddressesSize);
Status = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
NULL,
Addresses,
&AdapterAddressesSize);
if (Status)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
return 0;
}
for (pip = Addresses; pip != NULL; pip = pip->Next) {
Address = ((LPSOCKADDR_IN)pip->FirstUnicastAddress->Address.lpSockaddr)->sin_addr.S_un.S_addr;
if (Address != ntohl(INADDR_LOOPBACK))
break;
}
if (Address && Address != ntohl(INADDR_LOOPBACK))
{
ret = Address;
}
RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
return ret;
}
DNS_STATUS
WINAPI
Query_Main(LPCWSTR Name,
WORD Type,
DWORD Options,
PDNS_RECORD *QueryResultSet)
{
adns_state astate;
int quflags = (Options & DNS_QUERY_NO_RECURSION) == 0 ? adns_qf_search : 0;
int adns_error;
adns_answer *answer;
LPSTR CurrentName;
unsigned CNameLoop;
PFIXED_INFO network_info;
ULONG network_info_blen = 0;
DWORD network_info_result;
PIP_ADDR_STRING pip;
IP4_ADDRESS Address;
struct in_addr addr;
PCHAR HostWithDomainName;
PCHAR AnsiName;
size_t NameLen = 0;
if (Name == NULL)
return ERROR_INVALID_PARAMETER;
if (QueryResultSet == NULL)
return ERROR_INVALID_PARAMETER;
*QueryResultSet = NULL;
switch (Type)
{
case DNS_TYPE_A:
/* FIXME: how much instead of MAX_PATH? */
NameLen = WideCharToMultiByte(CP_ACP,
0,
Name,
-1,
NULL,
0,
NULL,
0);
AnsiName = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen);
if (NULL == AnsiName)
{
return ERROR_OUTOFMEMORY;
}
WideCharToMultiByte(CP_ACP,
0,
Name,
-1,
AnsiName,
NameLen,
NULL,
0);
NameLen--;
network_info_result = GetNetworkParams(NULL, &network_info_blen);
network_info = (PFIXED_INFO)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen);
if (NULL == network_info)
{
return ERROR_OUTOFMEMORY;
}
network_info_result = GetNetworkParams(network_info, &network_info_blen);
if (network_info_result != ERROR_SUCCESS)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
return network_info_result;
}
if ((Address = CheckForCurrentHostname(NameLen != 0 ? AnsiName : network_info->HostName, network_info)) != 0)
{
size_t TempLen = 2, StringLength = 0;
RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength);
TempLen += StringLength;
StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength);
TempLen += StringLength;
HostWithDomainName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen);
StringCchCopyA(HostWithDomainName, TempLen, network_info->HostName);
if (network_info->DomainName[0])
{
StringCchCatA(HostWithDomainName, TempLen, ".");
StringCchCatA(HostWithDomainName, TempLen, network_info->DomainName);
}
RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
*QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
if (NULL == *QueryResultSet)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
return ERROR_OUTOFMEMORY;
}
(*QueryResultSet)->pNext = NULL;
(*QueryResultSet)->wType = Type;
(*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
(*QueryResultSet)->Flags.S.Section = DnsSectionAnswer;
(*QueryResultSet)->Flags.S.CharSet = DnsCharSetUnicode;
(*QueryResultSet)->Data.A.IpAddress = Address;
(*QueryResultSet)->pName = (LPSTR)DnsCToW(HostWithDomainName);
RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
}
if ((Options & DNS_QUERY_NO_WIRE_QUERY) != 0)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
return ERROR_FILE_NOT_FOUND;
}
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);
if (!adns_numservers(astate))
{
/* There are no servers to query so bail out */
adns_finish(astate);
RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
return ERROR_FILE_NOT_FOUND;
}
/*
* 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.
*/
#define CNAME_LOOP_MAX 16
CurrentName = AnsiName;
for (CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++)
{
adns_error = adns_synchronous(astate, CurrentName, adns_r_addr, quflags, &answer);
if (adns_error != adns_s_ok)
{
adns_finish(astate);
if (CurrentName != AnsiName)
RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
}
if (answer && answer->rrs.addr)
{
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)->Flags.S.Section = DnsSectionAnswer;
(*QueryResultSet)->Flags.S.CharSet = DnsCharSetUnicode;
(*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;
}
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;
}
}
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. */
}
}
void
DnsIntFreeRecordList(PDNS_RECORD ToDelete)
{
UINT i;
PDNS_RECORD next = 0;
while(ToDelete)
{
if(ToDelete->pName)
RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->pName);
switch(ToDelete->wType)
{
case DNS_TYPE_CNAME:
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_MB:
case DNS_TYPE_MD:
case DNS_TYPE_MF:
case DNS_TYPE_MG:
case DNS_TYPE_MR:
RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.PTR.pNameHost);
break;
case DNS_TYPE_MINFO:
case DNS_TYPE_MX:
RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.MX.pNameExchange);
break;
case DNS_TYPE_HINFO:
for(i = 0; i < ToDelete->Data.TXT.dwStringCount; i++)
RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray[i]);
RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray);
break;
}
next = ToDelete->pNext;
RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete);
ToDelete = next;
}
}
BOOL
WINAPI
DnsFlushResolverCache(VOID)
{
DNS_STATUS Status = ERROR_SUCCESS;
DPRINT("DnsFlushResolverCache()\n");
RpcTryExcept
{
Status = R_ResolverFlushCache(NULL);
DPRINT("R_ResolverFlushCache() returned %lu\n", Status);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
Status = RpcExceptionCode();
DPRINT("Exception returned %lu\n", Status);
}
RpcEndExcept;
return (Status == ERROR_SUCCESS);
}
BOOL
WINAPI
DnsGetCacheDataTable(
_Out_ PDNS_CACHE_ENTRY *DnsCache)
{
DNS_STATUS Status = ERROR_SUCCESS;
PDNS_CACHE_ENTRY CacheEntries = NULL;
if (DnsCache == NULL)
return FALSE;
RpcTryExcept
{
Status = CRrReadCache(NULL,
&CacheEntries);
DPRINT("CRrReadCache() returned %lu\n", Status);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
Status = RpcExceptionCode();
DPRINT1("Exception returned %lu\n", Status);
}
RpcEndExcept;
if (Status != ERROR_SUCCESS)
return FALSE;
if (CacheEntries == NULL)
return FALSE;
*DnsCache = CacheEntries;
return TRUE;
}
DWORD
WINAPI
GetCurrentTimeInSeconds(VOID)
{
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/10000000ULL);
}