2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/dnsapi/dnsapi/query.c
5 * PURPOSE: DNSAPI functions built on the ADNS library.
6 * PROGRAMER: Art Yerkes
20 /* DnsQuery ****************************
21 * Begin a DNS query, and allow the result to be placed in the application
22 * supplied result pointer. The result can be manipulated with the record
25 * Name -- The DNS object to be queried.
26 * Type -- The type of records to be returned. These are
28 * Options -- Query options. DNS_QUERY_STANDARD is the base
29 * state, and every other option takes precedence.
30 * multiple options can be combined. Listed in
32 * Servers -- List of alternate servers (optional)
33 * QueryResultSet -- Pointer to the result pointer that will be filled
34 * when the response is available.
35 * Reserved -- Response as it appears on the wire. Optional.
39 DnsWToC(const WCHAR
*WideString
)
42 int AnsiLen
= WideCharToMultiByte(CP_ACP
,
52 AnsiString
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen
);
53 if (AnsiString
== NULL
)
57 WideCharToMultiByte(CP_ACP
,
70 DnsCToW(const CHAR
*NarrowString
)
73 int WideLen
= MultiByteToWideChar(CP_ACP
,
81 WideString
= RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen
* sizeof(WCHAR
));
82 if (WideString
== NULL
)
86 MultiByteToWideChar(CP_ACP
,
97 DnsWToUTF8(const WCHAR
*WideString
)
100 int AnsiLen
= WideCharToMultiByte(CP_UTF8
,
110 AnsiString
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen
);
111 if (AnsiString
== NULL
)
115 WideCharToMultiByte(CP_UTF8
,
128 DnsUTF8ToW(const CHAR
*NarrowString
)
131 int WideLen
= MultiByteToWideChar(CP_UTF8
,
139 WideString
= RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen
* sizeof(WCHAR
));
140 if (WideString
== NULL
)
144 MultiByteToWideChar(CP_UTF8
,
155 DnsQuery_CodePage(UINT CodePage
,
160 PDNS_RECORD
*QueryResultSet
,
166 PDNS_RECORD QueryResultWide
;
167 PDNS_RECORD ConvertedRecord
= 0, LastRecord
= 0;
170 return ERROR_INVALID_PARAMETER
;
171 if (QueryResultSet
== NULL
)
172 return ERROR_INVALID_PARAMETER
;
177 Buffer
= DnsCToW(Name
);
181 Buffer
= DnsUTF8ToW(Name
);
185 return ERROR_INVALID_PARAMETER
;
188 Status
= DnsQuery_W(Buffer
, Type
, Options
, Extra
, &QueryResultWide
, Reserved
);
190 while (Status
== ERROR_SUCCESS
&& QueryResultWide
)
192 switch (QueryResultWide
->wType
)
204 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
208 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATA
) + QueryResultWide
->Data
.TXT
.dwStringCount
);
212 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_NULL_DATA
) + QueryResultWide
->Data
.Null
.dwByteCount
);
215 if (ConvertedRecord
== NULL
)
218 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
220 DnsIntFreeRecordList(QueryResultWide
);
221 QueryResultSet
= NULL
;
222 return ERROR_OUTOFMEMORY
;
225 if (CodePage
== CP_ACP
)
226 ConvertedRecord
->pName
= DnsWToC((PWCHAR
)QueryResultWide
->pName
);
228 ConvertedRecord
->pName
= DnsWToUTF8((PWCHAR
)QueryResultWide
->pName
);
230 ConvertedRecord
->wType
= QueryResultWide
->wType
;
232 switch (QueryResultWide
->wType
)
236 ConvertedRecord
->wDataLength
= QueryResultWide
->wDataLength
;
237 memcpy(&ConvertedRecord
->Data
, &QueryResultWide
->Data
, QueryResultWide
->wDataLength
);
248 ConvertedRecord
->wDataLength
= sizeof(DNS_PTR_DATA
);
249 if (CodePage
== CP_ACP
)
250 ConvertedRecord
->Data
.PTR
.pNameHost
= DnsWToC((PWCHAR
)QueryResultWide
->Data
.PTR
.pNameHost
);
252 ConvertedRecord
->Data
.PTR
.pNameHost
= DnsWToUTF8((PWCHAR
)QueryResultWide
->Data
.PTR
.pNameHost
);
256 ConvertedRecord
->wDataLength
= sizeof(DNS_MINFO_DATA
);
257 if (CodePage
== CP_ACP
)
259 ConvertedRecord
->Data
.MINFO
.pNameMailbox
= DnsWToC((PWCHAR
)QueryResultWide
->Data
.MINFO
.pNameMailbox
);
260 ConvertedRecord
->Data
.MINFO
.pNameErrorsMailbox
= DnsWToC((PWCHAR
)QueryResultWide
->Data
.MINFO
.pNameErrorsMailbox
);
264 ConvertedRecord
->Data
.MINFO
.pNameMailbox
= DnsWToUTF8((PWCHAR
)QueryResultWide
->Data
.MINFO
.pNameMailbox
);
265 ConvertedRecord
->Data
.MINFO
.pNameErrorsMailbox
= DnsWToUTF8((PWCHAR
)QueryResultWide
->Data
.MINFO
.pNameErrorsMailbox
);
270 ConvertedRecord
->wDataLength
= sizeof(DNS_MX_DATA
);
271 if (CodePage
== CP_ACP
)
272 ConvertedRecord
->Data
.MX
.pNameExchange
= DnsWToC((PWCHAR
)QueryResultWide
->Data
.MX
.pNameExchange
);
274 ConvertedRecord
->Data
.MX
.pNameExchange
= DnsWToUTF8((PWCHAR
)QueryResultWide
->Data
.MX
.pNameExchange
);
275 ConvertedRecord
->Data
.MX
.wPreference
= QueryResultWide
->Data
.MX
.wPreference
;
279 ConvertedRecord
->wDataLength
= sizeof(DNS_TXT_DATA
) + (sizeof(PCHAR
) * QueryResultWide
->Data
.TXT
.dwStringCount
);
280 ConvertedRecord
->Data
.TXT
.dwStringCount
= QueryResultWide
->Data
.TXT
.dwStringCount
;
282 if (CodePage
== CP_ACP
)
283 for (i
= 0; i
< ConvertedRecord
->Data
.TXT
.dwStringCount
; i
++)
284 ConvertedRecord
->Data
.TXT
.pStringArray
[i
] = DnsWToC((PWCHAR
)QueryResultWide
->Data
.TXT
.pStringArray
[i
]);
286 for (i
= 0; i
< ConvertedRecord
->Data
.TXT
.dwStringCount
; i
++)
287 ConvertedRecord
->Data
.TXT
.pStringArray
[i
] = DnsWToUTF8((PWCHAR
)QueryResultWide
->Data
.TXT
.pStringArray
[i
]);
292 ConvertedRecord
->wDataLength
= sizeof(DNS_NULL_DATA
) + QueryResultWide
->Data
.Null
.dwByteCount
;
293 ConvertedRecord
->Data
.Null
.dwByteCount
= QueryResultWide
->Data
.Null
.dwByteCount
;
294 memcpy(&ConvertedRecord
->Data
.Null
.Data
, &QueryResultWide
->Data
.Null
.Data
, QueryResultWide
->Data
.Null
.dwByteCount
);
300 LastRecord
->pNext
= ConvertedRecord
;
301 LastRecord
= LastRecord
->pNext
;
305 LastRecord
= *QueryResultSet
= ConvertedRecord
;
308 QueryResultWide
= QueryResultWide
->pNext
;
312 LastRecord
->pNext
= 0;
315 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
317 if (QueryResultWide
) DnsIntFreeRecordList(QueryResultWide
);
323 DnsQuery_A(LPCSTR Name
,
327 PDNS_RECORD
*QueryResultSet
,
330 return DnsQuery_CodePage(CP_ACP
, Name
, Type
, Options
, Extra
, QueryResultSet
, Reserved
);
334 DnsQuery_UTF8(LPCSTR Name
,
338 PDNS_RECORD
*QueryResultSet
,
341 return DnsQuery_CodePage(CP_UTF8
, Name
, Type
, Options
, Extra
, QueryResultSet
, Reserved
);
345 *xstrsave(const WCHAR
*str
)
350 /* FIXME: how much instead of MAX_PATH? */
351 StringCbLengthW(str
, MAX_PATH
, &len
);
354 p
= RtlAllocateHeap(RtlGetProcessHeap(), 0, len
);
357 StringCbCopyW(p
, len
, str
);
363 *xstrsaveA(const CHAR
*str
)
368 /* FIXME: how much instead of MAX_PATH? */
369 StringCbLengthA(str
, MAX_PATH
, &len
);
372 p
= RtlAllocateHeap(RtlGetProcessHeap(), 0, len
);
375 StringCbCopyA(p
, len
, str
);
381 OpenNetworkDatabase(LPCWSTR Name
)
392 ExpandedPath
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
));
394 return INVALID_HANDLE_VALUE
;
396 /* Open the database path key */
397 ErrorCode
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
398 L
"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
402 if (ErrorCode
== NO_ERROR
)
404 /* Read the actual path */
405 ErrorCode
= RegQueryValueExW(DatabaseKey
,
412 DatabasePath
= HeapAlloc(GetProcessHeap(), 0, RegSize
);
415 HeapFree(GetProcessHeap(), 0, ExpandedPath
);
416 return INVALID_HANDLE_VALUE
;
419 /* Read the actual path */
420 ErrorCode
= RegQueryValueExW(DatabaseKey
,
424 (LPBYTE
)DatabasePath
,
428 RegCloseKey(DatabaseKey
);
430 /* Expand the name */
431 ExpandEnvironmentStringsW(DatabasePath
, ExpandedPath
, MAX_PATH
);
433 HeapFree(GetProcessHeap(), 0, DatabasePath
);
437 /* Use defalt path */
438 GetSystemDirectoryW(ExpandedPath
, MAX_PATH
);
439 StringCchLengthW(ExpandedPath
, MAX_PATH
, &StringLength
);
440 if (ExpandedPath
[StringLength
- 1] != L
'\\')
442 /* It isn't, so add it ourselves */
443 StringCchCatW(ExpandedPath
, MAX_PATH
, L
"\\");
445 StringCchCatW(ExpandedPath
, MAX_PATH
, L
"DRIVERS\\ETC\\");
448 /* Make sure that the path is backslash-terminated */
449 StringCchLengthW(ExpandedPath
, MAX_PATH
, &StringLength
);
450 if (ExpandedPath
[StringLength
- 1] != L
'\\')
452 /* It isn't, so add it ourselves */
453 StringCchCatW(ExpandedPath
, MAX_PATH
, L
"\\");
456 /* Add the database name */
457 StringCchCatW(ExpandedPath
, MAX_PATH
, Name
);
459 /* Return a handle to the file */
460 ret
= CreateFileW(ExpandedPath
,
465 FILE_ATTRIBUTE_NORMAL
,
468 HeapFree(GetProcessHeap(), 0, ExpandedPath
);
472 /* This function is far from perfect but it works enough */
474 CheckForCurrentHostname(CONST CHAR
* Name
, PFIXED_INFO network_info
)
477 DWORD AdapterAddressesSize
, Status
;
478 IP4_ADDRESS ret
= 0, Address
;
479 PIP_ADAPTER_ADDRESSES Addresses
= NULL
, pip
;
482 if (network_info
->DomainName
[0])
486 StringCchLengthA(network_info
->HostName
, sizeof(network_info
->HostName
), &StringLength
);
487 TempSize
+= StringLength
;
488 StringCchLengthA(network_info
->DomainName
, sizeof(network_info
->DomainName
), &StringLength
);
489 TempSize
+= StringLength
;
490 TempName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, TempSize
);
491 StringCchCopyA(TempName
, TempSize
, network_info
->HostName
);
492 StringCchCatA(TempName
, TempSize
, ".");
493 StringCchCatA(TempName
, TempSize
, network_info
->DomainName
);
497 TempName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, 1);
500 Found
= !stricmp(Name
, network_info
->HostName
) || !stricmp(Name
, TempName
);
501 RtlFreeHeap(RtlGetProcessHeap(), 0, TempName
);
506 /* get adapter info */
507 AdapterAddressesSize
= 0;
508 GetAdaptersAddresses(AF_INET
,
509 GAA_FLAG_SKIP_FRIENDLY_NAME
| GAA_FLAG_SKIP_DNS_SERVER
|
510 GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
,
513 &AdapterAddressesSize
);
514 if (!AdapterAddressesSize
)
518 Addresses
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AdapterAddressesSize
);
519 Status
= GetAdaptersAddresses(AF_INET
,
520 GAA_FLAG_SKIP_FRIENDLY_NAME
| GAA_FLAG_SKIP_DNS_SERVER
|
521 GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
,
524 &AdapterAddressesSize
);
527 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses
);
530 for (pip
= Addresses
; pip
!= NULL
; pip
= pip
->Next
) {
531 Address
= ((LPSOCKADDR_IN
)pip
->FirstUnicastAddress
->Address
.lpSockaddr
)->sin_addr
.S_un
.S_addr
;
532 if (Address
!= ntohl(INADDR_LOOPBACK
))
535 if (Address
&& Address
!= ntohl(INADDR_LOOPBACK
))
539 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses
);
544 ParseV4Address(LPCSTR AddressString
,
547 CHAR
* cp
= (CHAR
*)AddressString
;
550 DWORD parts
[4], *pp
= parts
;
553 if (!isdigit(*cp
)) return FALSE
;
557 * Collect number up to ``.''.
558 * Values are specified as for C:
559 * 0x=hex, 0=octal, other=decimal.
563 if (*++cp
== 'x' || *cp
== 'X')
570 val
= (val
* base
) + (c
- '0');
574 if (base
== 16 && isxdigit(c
)) {
575 val
= (val
<< 4) + (c
+ 10 - (islower(c
) ? 'a' : 'A'));
586 if (pp
>= parts
+ 4) return FALSE
;
592 * Check for trailing characters.
594 if (*cp
&& *cp
> ' ') return FALSE
;
596 if (pp
>= parts
+ 4) return FALSE
;
599 * Concoct the address according to
600 * the number of parts specified.
602 if ((DWORD
)(pp
- parts
) != 4) return FALSE
;
603 if (parts
[0] > 0xff || parts
[1] > 0xff || parts
[2] > 0xff || parts
[3] > 0xff) return FALSE
;
604 val
= (parts
[3] << 24) | (parts
[2] << 16) | (parts
[1] << 8) | parts
[0];
612 /* This function is far from perfect but it works enough */
614 FindEntryInHosts(CONST CHAR
* name
)
618 CHAR HostsDBData
[BUFSIZ
] = { 0 };
619 PCHAR AddressStr
, DnsName
= NULL
, AddrTerm
, NameSt
, NextLine
, ThisLine
, Comment
;
624 /* Open the network database */
625 HostsFile
= OpenNetworkDatabase(L
"hosts");
626 if (HostsFile
== INVALID_HANDLE_VALUE
)
628 WSASetLastError(WSANO_RECOVERY
);
632 while (!Found
&& ReadFile(HostsFile
,
633 HostsDBData
+ ValidData
,
634 sizeof(HostsDBData
) - ValidData
,
638 ValidData
+= ReadSize
;
640 NextLine
= ThisLine
= HostsDBData
;
642 /* Find the beginning of the next line */
643 while ((NextLine
< HostsDBData
+ ValidData
) &&
644 (*NextLine
!= '\r') &&
650 /* Zero and skip, so we can treat what we have as a string */
651 if (NextLine
> HostsDBData
+ ValidData
)
657 Comment
= strchr(ThisLine
, '#');
659 *Comment
= 0; /* Terminate at comment start */
661 AddressStr
= ThisLine
;
662 /* Find the first space separating the IP address from the DNS name */
663 AddrTerm
= strchr(ThisLine
, ' ');
666 /* Terminate the address string */
669 /* Find the last space before the DNS name */
670 NameSt
= strrchr(ThisLine
, ' ');
672 /* If there is only one space (the one we removed above), then just use the address terminator */
676 /* Move from the space to the first character of the DNS name */
681 if (!stricmp(name
, DnsName
) || !stricmp(name
, AddressStr
))
688 /* Get rid of everything we read so far */
689 while (NextLine
<= HostsDBData
+ ValidData
&&
695 if (HostsDBData
+ ValidData
- NextLine
<= 0)
698 memmove(HostsDBData
, NextLine
, HostsDBData
+ ValidData
- NextLine
);
699 ValidData
-= NextLine
- HostsDBData
;
702 CloseHandle(HostsFile
);
706 WSASetLastError(WSANO_DATA
);
710 if (strstr(AddressStr
, ":"))
712 WSASetLastError(WSAEINVAL
);
716 if (!ParseV4Address(AddressStr
, &Address
))
718 WSASetLastError(WSAEINVAL
);
726 DnsQuery_W(LPCWSTR Name
,
730 PDNS_RECORD
*QueryResultSet
,
734 DNS_STATUS Status
= ERROR_SUCCESS
;
736 DPRINT("DnsQuery_W()\n");
738 *QueryResultSet
= NULL
;
742 Status
= R_ResolverQuery(NULL
,
747 (DNS_RECORDW
**)QueryResultSet
);
748 DPRINT("R_ResolverQuery() returned %lu\n", Status
);
750 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
752 Status
= RpcExceptionCode();
753 DPRINT("Exception returned %lu\n", Status
);
763 Query_Main(LPCWSTR Name
,
766 PDNS_RECORD
*QueryResultSet
)
769 int quflags
= (Options
& DNS_QUERY_NO_RECURSION
) == 0 ? adns_qf_search
: 0;
773 unsigned i
, CNameLoop
;
774 PFIXED_INFO network_info
;
775 ULONG network_info_blen
= 0;
776 DWORD network_info_result
;
780 PCHAR HostWithDomainName
;
785 return ERROR_INVALID_PARAMETER
;
786 if (QueryResultSet
== NULL
)
787 return ERROR_INVALID_PARAMETER
;
789 *QueryResultSet
= NULL
;
794 /* FIXME: how much instead of MAX_PATH? */
795 NameLen
= WideCharToMultiByte(CP_ACP
,
803 AnsiName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen
);
804 if (NULL
== AnsiName
)
806 return ERROR_OUTOFMEMORY
;
808 WideCharToMultiByte(CP_ACP
,
817 /* Is it an IPv4 address? */
818 if (ParseV4Address(AnsiName
, &Address
))
820 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
821 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
823 if (NULL
== *QueryResultSet
)
825 return ERROR_OUTOFMEMORY
;
828 (*QueryResultSet
)->pNext
= NULL
;
829 (*QueryResultSet
)->wType
= Type
;
830 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
831 (*QueryResultSet
)->Data
.A
.IpAddress
= Address
;
833 (*QueryResultSet
)->pName
= (LPSTR
)xstrsave(Name
);
835 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
838 /* Check allowed characters
839 * According to RFC a-z,A-Z,0-9,-,_, but can't start or end with - or _
841 if (AnsiName
[0] == '-' || AnsiName
[0] == '_' || AnsiName
[NameLen
- 1] == '-' ||
842 AnsiName
[NameLen
- 1] == '_' || strstr(AnsiName
, "..") != NULL
)
844 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
845 return ERROR_INVALID_NAME
;
850 if (!((AnsiName
[i
] >= 'a' && AnsiName
[i
] <= 'z') ||
851 (AnsiName
[i
] >= 'A' && AnsiName
[i
] <= 'Z') ||
852 (AnsiName
[i
] >= '0' && AnsiName
[i
] <= '9') ||
853 AnsiName
[i
] == '-' || AnsiName
[i
] == '_' || AnsiName
[i
] == '.'))
855 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
856 return DNS_ERROR_INVALID_NAME_CHAR
;
861 if ((Options
& DNS_QUERY_NO_HOSTS_FILE
) == 0)
863 if ((Address
= FindEntryInHosts(AnsiName
)) != 0)
865 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
866 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
868 if (NULL
== *QueryResultSet
)
870 return ERROR_OUTOFMEMORY
;
873 (*QueryResultSet
)->pNext
= NULL
;
874 (*QueryResultSet
)->wType
= Type
;
875 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
876 (*QueryResultSet
)->Data
.A
.IpAddress
= Address
;
878 (*QueryResultSet
)->pName
= (LPSTR
)xstrsave(Name
);
880 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
884 network_info_result
= GetNetworkParams(NULL
, &network_info_blen
);
885 network_info
= (PFIXED_INFO
)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen
);
886 if (NULL
== network_info
)
888 return ERROR_OUTOFMEMORY
;
891 network_info_result
= GetNetworkParams(network_info
, &network_info_blen
);
892 if (network_info_result
!= ERROR_SUCCESS
)
894 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
895 return network_info_result
;
898 if ((Address
= CheckForCurrentHostname(NameLen
!= 0 ? AnsiName
: network_info
->HostName
, network_info
)) != 0)
900 size_t TempLen
= 2, StringLength
= 0;
901 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
902 StringCchLengthA(network_info
->HostName
, sizeof(network_info
->HostName
), &StringLength
);
903 TempLen
+= StringLength
;
904 StringCchLengthA(network_info
->DomainName
, sizeof(network_info
->DomainName
), &StringLength
);
905 TempLen
+= StringLength
;
906 HostWithDomainName
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen
);
907 StringCchCopyA(HostWithDomainName
, TempLen
, network_info
->HostName
);
908 if (network_info
->DomainName
[0])
910 StringCchCatA(HostWithDomainName
, TempLen
, ".");
911 StringCchCatA(HostWithDomainName
, TempLen
, network_info
->DomainName
);
913 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
914 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
916 if (NULL
== *QueryResultSet
)
918 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName
);
919 return ERROR_OUTOFMEMORY
;
922 (*QueryResultSet
)->pNext
= NULL
;
923 (*QueryResultSet
)->wType
= Type
;
924 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
925 (*QueryResultSet
)->Data
.A
.IpAddress
= Address
;
927 (*QueryResultSet
)->pName
= (LPSTR
)DnsCToW(HostWithDomainName
);
929 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName
);
930 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
933 if ((Options
& DNS_QUERY_NO_WIRE_QUERY
) != 0)
935 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
936 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
937 return ERROR_FILE_NOT_FOUND
;
940 adns_error
= adns_init(&astate
, adns_if_noenv
| adns_if_noerrprint
| adns_if_noserverwarn
, 0);
941 if (adns_error
!= adns_s_ok
)
943 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
944 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
945 return DnsIntTranslateAdnsToDNS_STATUS(adns_error
);
947 for (pip
= &(network_info
->DnsServerList
); pip
; pip
= pip
->Next
)
949 addr
.s_addr
= inet_addr(pip
->IpAddress
.String
);
950 if ((addr
.s_addr
!= INADDR_ANY
) && (addr
.s_addr
!= INADDR_NONE
))
951 adns_addserver(astate
, addr
);
953 if (network_info
->DomainName
[0])
955 adns_ccf_search(astate
, "LOCALDOMAIN", -1, network_info
->DomainName
);
957 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
959 if (!adns_numservers(astate
))
961 /* There are no servers to query so bail out */
963 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
964 return ERROR_FILE_NOT_FOUND
;
968 * adns doesn't resolve chained CNAME records (a CNAME which points to
969 * another CNAME pointing to another... pointing to an A record), according
970 * to a mailing list thread the authors believe that chained CNAME records
971 * are invalid and the DNS entries should be fixed. That's a nice academic
972 * standpoint, but there certainly are chained CNAME records out there,
973 * even some fairly major ones (at the time of this writing
974 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
975 * these fine, so we should too. So we loop here to try to resolve CNAME
976 * chains ourselves. Of course, there must be a limit to protect against
980 #define CNAME_LOOP_MAX 16
982 CurrentName
= AnsiName
;
984 for (CNameLoop
= 0; CNameLoop
< CNAME_LOOP_MAX
; CNameLoop
++)
986 adns_error
= adns_synchronous(astate
, CurrentName
, adns_r_addr
, quflags
, &answer
);
988 if (adns_error
!= adns_s_ok
)
992 if (CurrentName
!= AnsiName
)
993 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
995 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
996 return DnsIntTranslateAdnsToDNS_STATUS(adns_error
);
999 if (answer
&& answer
->rrs
.addr
)
1001 if (CurrentName
!= AnsiName
)
1002 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
1004 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
1005 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
1007 if (NULL
== *QueryResultSet
)
1009 adns_finish(astate
);
1010 return ERROR_OUTOFMEMORY
;
1013 (*QueryResultSet
)->pNext
= NULL
;
1014 (*QueryResultSet
)->wType
= Type
;
1015 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
1016 (*QueryResultSet
)->Data
.A
.IpAddress
= answer
->rrs
.addr
->addr
.inet
.sin_addr
.s_addr
;
1018 adns_finish(astate
);
1020 (*QueryResultSet
)->pName
= (LPSTR
)xstrsave(Name
);
1022 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
1025 if (NULL
== answer
|| adns_s_prohibitedcname
!= answer
->status
|| NULL
== answer
->cname
)
1027 adns_finish(astate
);
1029 if (CurrentName
!= AnsiName
)
1030 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
1032 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
1033 return ERROR_FILE_NOT_FOUND
;
1036 if (CurrentName
!= AnsiName
)
1037 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
1039 CurrentName
= (LPSTR
)xstrsaveA(answer
->cname
);
1043 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
1044 adns_finish(astate
);
1045 return ERROR_OUTOFMEMORY
;
1049 adns_finish(astate
);
1050 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
1051 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
1052 return ERROR_FILE_NOT_FOUND
;
1055 return ERROR_OUTOFMEMORY
; /* XXX arty: find a better error code. */
1060 DnsIntFreeRecordList(PDNS_RECORD ToDelete
)
1063 PDNS_RECORD next
= 0;
1068 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->pName
);
1070 switch(ToDelete
->wType
)
1072 case DNS_TYPE_CNAME
:
1080 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.PTR
.pNameHost
);
1083 case DNS_TYPE_MINFO
:
1085 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.MX
.pNameExchange
);
1088 case DNS_TYPE_HINFO
:
1089 for(i
= 0; i
< ToDelete
->Data
.TXT
.dwStringCount
; i
++)
1090 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
[i
]);
1092 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
);
1096 next
= ToDelete
->pNext
;
1097 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
);
1104 DnsFlushResolverCache(VOID
)
1106 DNS_STATUS Status
= ERROR_SUCCESS
;
1108 DPRINT("DnsFlushResolverCache()\n");
1112 Status
= R_ResolverFlushCache(NULL
);
1113 DPRINT("R_ResolverFlushCache() returned %lu\n", Status
);
1115 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1117 Status
= RpcExceptionCode();
1118 DPRINT("Exception returned %lu\n", Status
);
1122 return (Status
== ERROR_SUCCESS
);
1127 GetCurrentTimeInSeconds(VOID
)
1130 FILETIME Adjustment
;
1131 ULARGE_INTEGER lTime
, lAdj
;
1132 SYSTEMTIME st
= {1970, 1, 0, 1, 0, 0, 0};
1134 SystemTimeToFileTime(&st
, &Adjustment
);
1135 memcpy(&lAdj
, &Adjustment
, sizeof(lAdj
));
1136 GetSystemTimeAsFileTime(&Time
);
1137 memcpy(&lTime
, &Time
, sizeof(lTime
));
1138 lTime
.QuadPart
-= lAdj
.QuadPart
;
1139 return (DWORD
)(lTime
.QuadPart
/10000000ULL);