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
19 /* DnsQuery ****************************
20 * Begin a DNS query, and allow the result to be placed in the application
21 * supplied result pointer. The result can be manipulated with the record
24 * Name -- The DNS object to be queried.
25 * Type -- The type of records to be returned. These are
27 * Options -- Query options. DNS_QUERY_STANDARD is the base
28 * state, and every other option takes precedence.
29 * multiple options can be combined. Listed in
31 * Servers -- List of alternate servers (optional)
32 * QueryResultSet -- Pointer to the result pointer that will be filled
33 * when the response is available.
34 * Reserved -- Response as it appears on the wire. Optional.
38 DnsWToC(const WCHAR
*WideString
)
41 int AnsiLen
= WideCharToMultiByte(CP_ACP
,
51 AnsiString
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen
);
52 if (AnsiString
== NULL
)
56 WideCharToMultiByte(CP_ACP
,
69 DnsCToW(const CHAR
*NarrowString
)
72 int WideLen
= MultiByteToWideChar(CP_ACP
,
80 WideLen
*= sizeof(WCHAR
);
81 WideString
= RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen
);
82 if (WideString
== NULL
)
86 MultiByteToWideChar(CP_ACP
,
97 DnsQuery_A(LPCSTR Name
,
101 PDNS_RECORD
*QueryResultSet
,
107 PDNS_RECORD QueryResultWide
;
108 PDNS_RECORD ConvertedRecord
= 0, LastRecord
= 0;
111 return ERROR_INVALID_PARAMETER
;
112 if (QueryResultSet
== NULL
)
113 return ERROR_INVALID_PARAMETER
;
115 Buffer
= DnsCToW(Name
);
117 Status
= DnsQuery_W(Buffer
, Type
, Options
, Servers
, &QueryResultWide
, Reserved
);
119 while (Status
== ERROR_SUCCESS
&& QueryResultWide
)
121 switch (QueryResultWide
->wType
)
125 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
126 ConvertedRecord
->pName
= DnsWToC((PWCHAR
)QueryResultWide
->pName
);
127 ConvertedRecord
->wType
= QueryResultWide
->wType
;
128 ConvertedRecord
->wDataLength
= QueryResultWide
->wDataLength
;
129 memcpy(&ConvertedRecord
->Data
, &QueryResultWide
->Data
, QueryResultWide
->wDataLength
);
140 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
141 ConvertedRecord
->pName
= DnsWToC((PWCHAR
)QueryResultWide
->pName
);
142 ConvertedRecord
->wType
= QueryResultWide
->wType
;
143 ConvertedRecord
->wDataLength
= sizeof(DNS_PTR_DATA
);
144 ConvertedRecord
->Data
.PTR
.pNameHost
= DnsWToC((PWCHAR
)QueryResultWide
->Data
.PTR
.pNameHost
);
148 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
149 ConvertedRecord
->pName
= DnsWToC((PWCHAR
)QueryResultWide
->pName
);
150 ConvertedRecord
->wType
= QueryResultWide
->wType
;
151 ConvertedRecord
->wDataLength
= sizeof(DNS_MINFO_DATA
);
152 ConvertedRecord
->Data
.MINFO
.pNameMailbox
= DnsWToC((PWCHAR
)QueryResultWide
->Data
.MINFO
.pNameMailbox
);
153 ConvertedRecord
->Data
.MINFO
.pNameErrorsMailbox
= DnsWToC((PWCHAR
)QueryResultWide
->Data
.MINFO
.pNameErrorsMailbox
);
157 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
158 ConvertedRecord
->pName
= DnsWToC((PWCHAR
)QueryResultWide
->pName
);
159 ConvertedRecord
->wType
= QueryResultWide
->wType
;
160 ConvertedRecord
->wDataLength
= sizeof(DNS_MX_DATA
);
161 ConvertedRecord
->Data
.MX
.pNameExchange
= DnsWToC((PWCHAR
)QueryResultWide
->Data
.MX
.pNameExchange
);
162 ConvertedRecord
->Data
.MX
.wPreference
= QueryResultWide
->Data
.MX
.wPreference
;
166 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATA
) + QueryResultWide
->Data
.TXT
.dwStringCount
);
167 ConvertedRecord
->pName
= DnsWToC((PWCHAR
)QueryResultWide
->pName
);
168 ConvertedRecord
->wType
= QueryResultWide
->wType
;
169 ConvertedRecord
->wDataLength
= sizeof(DNS_TXT_DATA
) + (sizeof(PCHAR
) * QueryResultWide
->Data
.TXT
.dwStringCount
);
170 ConvertedRecord
->Data
.TXT
.dwStringCount
= QueryResultWide
->Data
.TXT
.dwStringCount
;
172 for (i
= 0; i
< ConvertedRecord
->Data
.TXT
.dwStringCount
; i
++)
173 ConvertedRecord
->Data
.TXT
.pStringArray
[i
] = DnsWToC((PWCHAR
)QueryResultWide
->Data
.TXT
.pStringArray
[i
]);
178 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_NULL_DATA
) + QueryResultWide
->Data
.Null
.dwByteCount
);
179 ConvertedRecord
->pName
= DnsWToC((PWCHAR
)QueryResultWide
->pName
);
180 ConvertedRecord
->wType
= QueryResultWide
->wType
;
181 ConvertedRecord
->wDataLength
= sizeof(DNS_NULL_DATA
) + QueryResultWide
->Data
.Null
.dwByteCount
;
182 ConvertedRecord
->Data
.Null
.dwByteCount
= QueryResultWide
->Data
.Null
.dwByteCount
;
183 memcpy(&ConvertedRecord
->Data
.Null
.Data
, &QueryResultWide
->Data
.Null
.Data
, QueryResultWide
->Data
.Null
.dwByteCount
);
189 LastRecord
->pNext
= ConvertedRecord
;
190 LastRecord
= LastRecord
->pNext
;
194 LastRecord
= *QueryResultSet
= ConvertedRecord
;
197 QueryResultWide
= QueryResultWide
->pNext
;
201 LastRecord
->pNext
= 0;
204 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
206 if (QueryResultWide
) DnsIntFreeRecordList(QueryResultWide
);
212 *xstrsave(const WCHAR
*str
)
217 /* FIXME: how much instead of MAX_PATH? */
218 StringCbLengthW(str
, MAX_PATH
, &len
);
221 p
= RtlAllocateHeap(RtlGetProcessHeap(), 0, len
);
224 StringCbCopyW(p
, len
, str
);
230 *xstrsaveA(const CHAR
*str
)
235 /* FIXME: how much instead of MAX_PATH? */
236 StringCbLengthA(str
, MAX_PATH
, &len
);
239 p
= RtlAllocateHeap(RtlGetProcessHeap(), 0, len
);
242 StringCbCopyA(p
, len
, str
);
248 OpenNetworkDatabase(LPCWSTR Name
)
259 ExpandedPath
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
));
261 return INVALID_HANDLE_VALUE
;
263 /* Open the database path key */
264 ErrorCode
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
265 L
"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
269 if (ErrorCode
== NO_ERROR
)
271 /* Read the actual path */
272 ErrorCode
= RegQueryValueExW(DatabaseKey
,
279 DatabasePath
= HeapAlloc(GetProcessHeap(), 0, RegSize
);
282 HeapFree(GetProcessHeap(), 0, ExpandedPath
);
283 return INVALID_HANDLE_VALUE
;
286 /* Read the actual path */
287 ErrorCode
= RegQueryValueExW(DatabaseKey
,
291 (LPBYTE
)DatabasePath
,
295 RegCloseKey(DatabaseKey
);
297 /* Expand the name */
298 ExpandEnvironmentStringsW(DatabasePath
, ExpandedPath
, MAX_PATH
);
300 HeapFree(GetProcessHeap(), 0, DatabasePath
);
304 /* Use defalt path */
305 GetSystemDirectoryW(ExpandedPath
, MAX_PATH
);
306 StringCchLength(ExpandedPath
, MAX_PATH
, &StringLength
);
307 if (ExpandedPath
[StringLength
- 1] != L
'\\')
309 /* It isn't, so add it ourselves */
310 StringCchCat(ExpandedPath
, MAX_PATH
, L
"\\");
312 StringCchCat(ExpandedPath
, MAX_PATH
, L
"DRIVERS\\ETC\\");
315 /* Make sure that the path is backslash-terminated */
316 StringCchLength(ExpandedPath
, MAX_PATH
, &StringLength
);
317 if (ExpandedPath
[StringLength
- 1] != L
'\\')
319 /* It isn't, so add it ourselves */
320 StringCchCat(ExpandedPath
, MAX_PATH
, L
"\\");
323 /* Add the database name */
324 StringCchCat(ExpandedPath
, MAX_PATH
, Name
);
326 /* Return a handle to the file */
327 ret
= CreateFileW(ExpandedPath
,
332 FILE_ATTRIBUTE_NORMAL
,
335 HeapFree(GetProcessHeap(), 0, ExpandedPath
);
339 /* This function is far from perfect but it works enough */
341 CheckForCurrentHostname(CONST CHAR
* Name
, PFIXED_INFO network_info
)
344 DWORD AdapterAddressesSize
, Status
;
345 IP4_ADDRESS ret
= 0, Address
;
346 PIP_ADAPTER_ADDRESSES Addresses
= NULL
, pip
;
349 if (network_info
->DomainName
)
353 StringCchLengthA(network_info
->HostName
, sizeof(network_info
->HostName
), &StringLength
);
354 TempSize
+= StringLength
;
355 StringCchLengthA(network_info
->DomainName
, sizeof(network_info
->DomainName
), &StringLength
);
356 TempSize
+= StringLength
;
357 TempName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, TempSize
);
358 StringCchCopyA(TempName
, TempSize
, network_info
->HostName
);
359 StringCchCatA(TempName
, TempSize
, ".");
360 StringCchCatA(TempName
, TempSize
, network_info
->DomainName
);
364 TempName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, 1);
367 Found
= !stricmp(Name
, network_info
->HostName
) || !stricmp(Name
, TempName
);
368 RtlFreeHeap(RtlGetProcessHeap(), 0, TempName
);
373 /* get adapter info */
374 AdapterAddressesSize
= 0;
375 GetAdaptersAddresses(AF_INET
,
376 GAA_FLAG_SKIP_FRIENDLY_NAME
| GAA_FLAG_SKIP_DNS_SERVER
|
377 GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
,
380 &AdapterAddressesSize
);
381 if (!AdapterAddressesSize
)
385 Addresses
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AdapterAddressesSize
);
386 Status
= GetAdaptersAddresses(AF_INET
,
387 GAA_FLAG_SKIP_FRIENDLY_NAME
| GAA_FLAG_SKIP_DNS_SERVER
|
388 GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
,
391 &AdapterAddressesSize
);
394 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses
);
397 for (pip
= Addresses
; pip
!= NULL
; pip
= pip
->Next
) {
398 Address
= ((LPSOCKADDR_IN
)pip
->FirstUnicastAddress
->Address
.lpSockaddr
)->sin_addr
.S_un
.S_addr
;
399 if (Address
!= ntohl(INADDR_LOOPBACK
))
402 if (Address
&& Address
!= ntohl(INADDR_LOOPBACK
))
406 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses
);
411 ParseV4Address(LPCSTR AddressString
,
414 CHAR
* cp
= (CHAR
*)AddressString
;
417 DWORD parts
[4], *pp
= parts
;
420 if (!isdigit(*cp
)) return FALSE
;
424 * Collect number up to ``.''.
425 * Values are specified as for C:
426 * 0x=hex, 0=octal, other=decimal.
430 if (*++cp
== 'x' || *cp
== 'X')
437 val
= (val
* base
) + (c
- '0');
441 if (base
== 16 && isxdigit(c
)) {
442 val
= (val
<< 4) + (c
+ 10 - (islower(c
) ? 'a' : 'A'));
453 if (pp
>= parts
+ 4) return FALSE
;
459 * Check for trailing characters.
461 if (*cp
&& *cp
> ' ') return FALSE
;
465 * Concoct the address according to
466 * the number of parts specified.
468 if ((DWORD
)(pp
- parts
) != 4) return FALSE
;
469 if (parts
[0] > 0xff || parts
[1] > 0xff || parts
[2] > 0xff || parts
[3] > 0xff) return FALSE
;
470 val
= (parts
[3] << 24) | (parts
[2] << 16) | (parts
[1] << 8) | parts
[0];
478 /* This function is far from perfect but it works enough */
480 FindEntryInHosts(CONST CHAR
* name
)
484 CHAR HostsDBData
[BUFSIZ
] = { 0 };
485 PCHAR AddressStr
, DnsName
= NULL
, AddrTerm
, NameSt
, NextLine
, ThisLine
, Comment
;
490 /* Open the network database */
491 HostsFile
= OpenNetworkDatabase(L
"hosts");
492 if (HostsFile
== INVALID_HANDLE_VALUE
)
494 WSASetLastError(WSANO_RECOVERY
);
498 while (!Found
&& ReadFile(HostsFile
,
499 HostsDBData
+ ValidData
,
500 sizeof(HostsDBData
) - ValidData
,
504 ValidData
+= ReadSize
;
506 NextLine
= ThisLine
= HostsDBData
;
508 /* Find the beginning of the next line */
509 while ((NextLine
< HostsDBData
+ ValidData
) &&
510 (*NextLine
!= '\r') &&
516 /* Zero and skip, so we can treat what we have as a string */
517 if (NextLine
> HostsDBData
+ ValidData
)
523 Comment
= strchr(ThisLine
, '#');
525 *Comment
= 0; /* Terminate at comment start */
527 AddressStr
= ThisLine
;
528 /* Find the first space separating the IP address from the DNS name */
529 AddrTerm
= strchr(ThisLine
, ' ');
532 /* Terminate the address string */
535 /* Find the last space before the DNS name */
536 NameSt
= strrchr(ThisLine
, ' ');
538 /* If there is only one space (the one we removed above), then just use the address terminator */
542 /* Move from the space to the first character of the DNS name */
547 if (!stricmp(name
, DnsName
) || !stricmp(name
, AddressStr
))
554 /* Get rid of everything we read so far */
555 while (NextLine
<= HostsDBData
+ ValidData
&&
561 if (HostsDBData
+ ValidData
- NextLine
<= 0)
564 memmove(HostsDBData
, NextLine
, HostsDBData
+ ValidData
- NextLine
);
565 ValidData
-= NextLine
- HostsDBData
;
568 CloseHandle(HostsFile
);
572 WSASetLastError(WSANO_DATA
);
576 if (strstr(AddressStr
, ":"))
578 WSASetLastError(WSAEINVAL
);
582 if (!ParseV4Address(AddressStr
, &Address
))
584 WSASetLastError(WSAEINVAL
);
592 DnsQuery_W(LPCWSTR Name
,
596 PDNS_RECORD
*QueryResultSet
,
600 int quflags
= (Options
& DNS_QUERY_NO_RECURSION
) == 0 ? adns_qf_search
: 0;
604 unsigned i
, CNameLoop
;
605 PFIXED_INFO network_info
;
606 ULONG network_info_blen
= 0;
607 DWORD network_info_result
;
611 PCHAR HostWithDomainName
;
616 return ERROR_INVALID_PARAMETER
;
617 if (QueryResultSet
== NULL
)
618 return ERROR_INVALID_PARAMETER
;
619 if ((Options
& DNS_QUERY_WIRE_ONLY
) != 0 && (Options
& DNS_QUERY_NO_WIRE_QUERY
) != 0)
620 return ERROR_INVALID_PARAMETER
;
627 /* FIXME: how much instead of MAX_PATH? */
628 NameLen
= WideCharToMultiByte(CP_ACP
,
636 AnsiName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen
);
637 if (NULL
== AnsiName
)
639 return ERROR_OUTOFMEMORY
;
641 WideCharToMultiByte(CP_ACP
,
650 /* Is it an IPv4 address? */
651 if (ParseV4Address(AnsiName
, &Address
))
653 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
654 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
656 if (NULL
== *QueryResultSet
)
658 return ERROR_OUTOFMEMORY
;
661 (*QueryResultSet
)->pNext
= NULL
;
662 (*QueryResultSet
)->wType
= Type
;
663 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
664 (*QueryResultSet
)->Data
.A
.IpAddress
= Address
;
666 (*QueryResultSet
)->pName
= (LPSTR
)xstrsave(Name
);
668 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
671 /* Check allowed characters
672 * According to RFC a-z,A-Z,0-9,-,_, but can't start or end with - or _
674 if (AnsiName
[0] == '-' || AnsiName
[0] == '_' || AnsiName
[NameLen
- 1] == '-' ||
675 AnsiName
[NameLen
- 1] == '_' || strstr(AnsiName
, "..") != NULL
)
677 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
678 return ERROR_INVALID_NAME
;
683 if (!((AnsiName
[i
] >= 'a' && AnsiName
[i
] <= 'z') ||
684 (AnsiName
[i
] >= 'A' && AnsiName
[i
] <= 'Z') ||
685 (AnsiName
[i
] >= '0' && AnsiName
[i
] <= '9') ||
686 AnsiName
[i
] == '-' || AnsiName
[i
] == '_' || AnsiName
[i
] == '.'))
688 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
689 return ERROR_INVALID_NAME
;
694 if ((Options
& DNS_QUERY_NO_HOSTS_FILE
) == 0)
696 if ((Address
= FindEntryInHosts(AnsiName
)) != 0)
698 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
699 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
701 if (NULL
== *QueryResultSet
)
703 return ERROR_OUTOFMEMORY
;
706 (*QueryResultSet
)->pNext
= NULL
;
707 (*QueryResultSet
)->wType
= Type
;
708 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
709 (*QueryResultSet
)->Data
.A
.IpAddress
= Address
;
711 (*QueryResultSet
)->pName
= (LPSTR
)xstrsave(Name
);
713 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
717 network_info_result
= GetNetworkParams(NULL
, &network_info_blen
);
718 network_info
= (PFIXED_INFO
)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen
);
719 if (NULL
== network_info
)
721 return ERROR_OUTOFMEMORY
;
724 network_info_result
= GetNetworkParams(network_info
, &network_info_blen
);
725 if (network_info_result
!= ERROR_SUCCESS
)
727 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
728 return network_info_result
;
731 if ((Address
= CheckForCurrentHostname(NameLen
!= 0 ? AnsiName
: network_info
->HostName
, network_info
)) != 0)
733 size_t TempLen
= 2, StringLength
= 0;
734 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
735 StringCchLengthA(network_info
->HostName
, sizeof(network_info
->HostName
), &StringLength
);
736 TempLen
+= StringLength
;
737 StringCchLengthA(network_info
->DomainName
, sizeof(network_info
->DomainName
), &StringLength
);
738 TempLen
+= StringLength
;
739 HostWithDomainName
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen
);
740 StringCchCopyA(HostWithDomainName
, TempLen
, network_info
->HostName
);
741 if (network_info
->DomainName
)
743 StringCchCatA(HostWithDomainName
, TempLen
, ".");
744 StringCchCatA(HostWithDomainName
, TempLen
, network_info
->DomainName
);
746 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
747 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
749 if (NULL
== *QueryResultSet
)
751 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName
);
752 return ERROR_OUTOFMEMORY
;
755 (*QueryResultSet
)->pNext
= NULL
;
756 (*QueryResultSet
)->wType
= Type
;
757 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
758 (*QueryResultSet
)->Data
.A
.IpAddress
= Address
;
760 (*QueryResultSet
)->pName
= (LPSTR
)DnsCToW(HostWithDomainName
);
762 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName
);
763 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
766 if ((Options
& DNS_QUERY_NO_WIRE_QUERY
) != 0)
768 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
769 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
770 return ERROR_FILE_NOT_FOUND
;
773 adns_error
= adns_init(&astate
, adns_if_noenv
| adns_if_noerrprint
| adns_if_noserverwarn
, 0);
774 if (adns_error
!= adns_s_ok
)
776 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
777 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
778 return DnsIntTranslateAdnsToDNS_STATUS(adns_error
);
780 for (pip
= &(network_info
->DnsServerList
); pip
; pip
= pip
->Next
)
782 addr
.s_addr
= inet_addr(pip
->IpAddress
.String
);
783 if ((addr
.s_addr
!= INADDR_ANY
) && (addr
.s_addr
!= INADDR_NONE
))
784 adns_addserver(astate
, addr
);
786 if (network_info
->DomainName
)
788 adns_ccf_search(astate
, "LOCALDOMAIN", -1, network_info
->DomainName
);
790 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
794 for (i
= 0; i
< Servers
->AddrCount
; i
++)
796 adns_addserver(astate
, *((struct in_addr
*)&Servers
->AddrArray
[i
]));
801 * adns doesn't resolve chained CNAME records (a CNAME which points to
802 * another CNAME pointing to another... pointing to an A record), according
803 * to a mailing list thread the authors believe that chained CNAME records
804 * are invalid and the DNS entries should be fixed. That's a nice academic
805 * standpoint, but there certainly are chained CNAME records out there,
806 * even some fairly major ones (at the time of this writing
807 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
808 * these fine, so we should too. So we loop here to try to resolve CNAME
809 * chains ourselves. Of course, there must be a limit to protect against
813 #define CNAME_LOOP_MAX 16
815 CurrentName
= AnsiName
;
817 for (CNameLoop
= 0; CNameLoop
< CNAME_LOOP_MAX
; CNameLoop
++)
819 adns_error
= adns_synchronous(astate
, CurrentName
, adns_r_addr
, quflags
, &answer
);
821 if (adns_error
!= adns_s_ok
)
825 if (CurrentName
!= AnsiName
)
826 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
828 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
829 return DnsIntTranslateAdnsToDNS_STATUS(adns_error
);
832 if (answer
&& answer
->rrs
.addr
)
834 if (CurrentName
!= AnsiName
)
835 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
837 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
838 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
840 if (NULL
== *QueryResultSet
)
843 return ERROR_OUTOFMEMORY
;
846 (*QueryResultSet
)->pNext
= NULL
;
847 (*QueryResultSet
)->wType
= Type
;
848 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
849 (*QueryResultSet
)->Data
.A
.IpAddress
= answer
->rrs
.addr
->addr
.inet
.sin_addr
.s_addr
;
853 (*QueryResultSet
)->pName
= (LPSTR
)xstrsave(Name
);
855 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
858 if (NULL
== answer
|| adns_s_prohibitedcname
!= answer
->status
|| NULL
== answer
->cname
)
862 if (CurrentName
!= AnsiName
)
863 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
865 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
866 return ERROR_FILE_NOT_FOUND
;
869 if (CurrentName
!= AnsiName
)
870 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
872 CurrentName
= (LPSTR
)xstrsaveA(answer
->cname
);
876 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
878 return ERROR_OUTOFMEMORY
;
883 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
884 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
885 return ERROR_FILE_NOT_FOUND
;
888 return ERROR_OUTOFMEMORY
; /* XXX arty: find a better error code. */
893 DnsQuery_UTF8(LPCSTR Name
,
897 PDNS_RECORD
*QueryResultSet
,
901 return ERROR_OUTOFMEMORY
;
905 DnsIntFreeRecordList(PDNS_RECORD ToDelete
)
908 PDNS_RECORD next
= 0;
913 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->pName
);
915 switch(ToDelete
->wType
)
925 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.PTR
.pNameHost
);
930 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.MX
.pNameExchange
);
934 for(i
= 0; i
< ToDelete
->Data
.TXT
.dwStringCount
; i
++)
935 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
[i
]);
937 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
);
941 next
= ToDelete
->pNext
;
942 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
);