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 StringCchLengthW(ExpandedPath
, MAX_PATH
, &StringLength
);
307 if (ExpandedPath
[StringLength
- 1] != L
'\\')
309 /* It isn't, so add it ourselves */
310 StringCchCatW(ExpandedPath
, MAX_PATH
, L
"\\");
312 StringCchCatW(ExpandedPath
, MAX_PATH
, L
"DRIVERS\\ETC\\");
315 /* Make sure that the path is backslash-terminated */
316 StringCchLengthW(ExpandedPath
, MAX_PATH
, &StringLength
);
317 if (ExpandedPath
[StringLength
- 1] != L
'\\')
319 /* It isn't, so add it ourselves */
320 StringCchCatW(ExpandedPath
, MAX_PATH
, L
"\\");
323 /* Add the database name */
324 StringCchCatW(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
[0])
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
;
463 if (pp
>= parts
+ 4) return FALSE
;
466 * Concoct the address according to
467 * the number of parts specified.
469 if ((DWORD
)(pp
- parts
) != 4) return FALSE
;
470 if (parts
[0] > 0xff || parts
[1] > 0xff || parts
[2] > 0xff || parts
[3] > 0xff) return FALSE
;
471 val
= (parts
[3] << 24) | (parts
[2] << 16) | (parts
[1] << 8) | parts
[0];
479 /* This function is far from perfect but it works enough */
481 FindEntryInHosts(CONST CHAR
* name
)
485 CHAR HostsDBData
[BUFSIZ
] = { 0 };
486 PCHAR AddressStr
, DnsName
= NULL
, AddrTerm
, NameSt
, NextLine
, ThisLine
, Comment
;
491 /* Open the network database */
492 HostsFile
= OpenNetworkDatabase(L
"hosts");
493 if (HostsFile
== INVALID_HANDLE_VALUE
)
495 WSASetLastError(WSANO_RECOVERY
);
499 while (!Found
&& ReadFile(HostsFile
,
500 HostsDBData
+ ValidData
,
501 sizeof(HostsDBData
) - ValidData
,
505 ValidData
+= ReadSize
;
507 NextLine
= ThisLine
= HostsDBData
;
509 /* Find the beginning of the next line */
510 while ((NextLine
< HostsDBData
+ ValidData
) &&
511 (*NextLine
!= '\r') &&
517 /* Zero and skip, so we can treat what we have as a string */
518 if (NextLine
> HostsDBData
+ ValidData
)
524 Comment
= strchr(ThisLine
, '#');
526 *Comment
= 0; /* Terminate at comment start */
528 AddressStr
= ThisLine
;
529 /* Find the first space separating the IP address from the DNS name */
530 AddrTerm
= strchr(ThisLine
, ' ');
533 /* Terminate the address string */
536 /* Find the last space before the DNS name */
537 NameSt
= strrchr(ThisLine
, ' ');
539 /* If there is only one space (the one we removed above), then just use the address terminator */
543 /* Move from the space to the first character of the DNS name */
548 if (!stricmp(name
, DnsName
) || !stricmp(name
, AddressStr
))
555 /* Get rid of everything we read so far */
556 while (NextLine
<= HostsDBData
+ ValidData
&&
562 if (HostsDBData
+ ValidData
- NextLine
<= 0)
565 memmove(HostsDBData
, NextLine
, HostsDBData
+ ValidData
- NextLine
);
566 ValidData
-= NextLine
- HostsDBData
;
569 CloseHandle(HostsFile
);
573 WSASetLastError(WSANO_DATA
);
577 if (strstr(AddressStr
, ":"))
579 WSASetLastError(WSAEINVAL
);
583 if (!ParseV4Address(AddressStr
, &Address
))
585 WSASetLastError(WSAEINVAL
);
593 DnsQuery_W(LPCWSTR Name
,
597 PDNS_RECORD
*QueryResultSet
,
601 int quflags
= (Options
& DNS_QUERY_NO_RECURSION
) == 0 ? adns_qf_search
: 0;
605 unsigned i
, CNameLoop
;
606 PFIXED_INFO network_info
;
607 ULONG network_info_blen
= 0;
608 DWORD network_info_result
;
612 PCHAR HostWithDomainName
;
617 return ERROR_INVALID_PARAMETER
;
618 if (QueryResultSet
== NULL
)
619 return ERROR_INVALID_PARAMETER
;
620 if ((Options
& DNS_QUERY_WIRE_ONLY
) != 0 && (Options
& DNS_QUERY_NO_WIRE_QUERY
) != 0)
621 return ERROR_INVALID_PARAMETER
;
628 /* FIXME: how much instead of MAX_PATH? */
629 NameLen
= WideCharToMultiByte(CP_ACP
,
637 AnsiName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen
);
638 if (NULL
== AnsiName
)
640 return ERROR_OUTOFMEMORY
;
642 WideCharToMultiByte(CP_ACP
,
651 /* Is it an IPv4 address? */
652 if (ParseV4Address(AnsiName
, &Address
))
654 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
655 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
657 if (NULL
== *QueryResultSet
)
659 return ERROR_OUTOFMEMORY
;
662 (*QueryResultSet
)->pNext
= NULL
;
663 (*QueryResultSet
)->wType
= Type
;
664 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
665 (*QueryResultSet
)->Data
.A
.IpAddress
= Address
;
667 (*QueryResultSet
)->pName
= (LPSTR
)xstrsave(Name
);
669 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
672 /* Check allowed characters
673 * According to RFC a-z,A-Z,0-9,-,_, but can't start or end with - or _
675 if (AnsiName
[0] == '-' || AnsiName
[0] == '_' || AnsiName
[NameLen
- 1] == '-' ||
676 AnsiName
[NameLen
- 1] == '_' || strstr(AnsiName
, "..") != NULL
)
678 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
679 return ERROR_INVALID_NAME
;
684 if (!((AnsiName
[i
] >= 'a' && AnsiName
[i
] <= 'z') ||
685 (AnsiName
[i
] >= 'A' && AnsiName
[i
] <= 'Z') ||
686 (AnsiName
[i
] >= '0' && AnsiName
[i
] <= '9') ||
687 AnsiName
[i
] == '-' || AnsiName
[i
] == '_' || AnsiName
[i
] == '.'))
689 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
690 return ERROR_INVALID_NAME
;
695 if ((Options
& DNS_QUERY_NO_HOSTS_FILE
) == 0)
697 if ((Address
= FindEntryInHosts(AnsiName
)) != 0)
699 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
700 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
702 if (NULL
== *QueryResultSet
)
704 return ERROR_OUTOFMEMORY
;
707 (*QueryResultSet
)->pNext
= NULL
;
708 (*QueryResultSet
)->wType
= Type
;
709 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
710 (*QueryResultSet
)->Data
.A
.IpAddress
= Address
;
712 (*QueryResultSet
)->pName
= (LPSTR
)xstrsave(Name
);
714 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
718 network_info_result
= GetNetworkParams(NULL
, &network_info_blen
);
719 network_info
= (PFIXED_INFO
)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen
);
720 if (NULL
== network_info
)
722 return ERROR_OUTOFMEMORY
;
725 network_info_result
= GetNetworkParams(network_info
, &network_info_blen
);
726 if (network_info_result
!= ERROR_SUCCESS
)
728 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
729 return network_info_result
;
732 if ((Address
= CheckForCurrentHostname(NameLen
!= 0 ? AnsiName
: network_info
->HostName
, network_info
)) != 0)
734 size_t TempLen
= 2, StringLength
= 0;
735 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
736 StringCchLengthA(network_info
->HostName
, sizeof(network_info
->HostName
), &StringLength
);
737 TempLen
+= StringLength
;
738 StringCchLengthA(network_info
->DomainName
, sizeof(network_info
->DomainName
), &StringLength
);
739 TempLen
+= StringLength
;
740 HostWithDomainName
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen
);
741 StringCchCopyA(HostWithDomainName
, TempLen
, network_info
->HostName
);
742 if (network_info
->DomainName
[0])
744 StringCchCatA(HostWithDomainName
, TempLen
, ".");
745 StringCchCatA(HostWithDomainName
, TempLen
, network_info
->DomainName
);
747 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
748 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
750 if (NULL
== *QueryResultSet
)
752 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName
);
753 return ERROR_OUTOFMEMORY
;
756 (*QueryResultSet
)->pNext
= NULL
;
757 (*QueryResultSet
)->wType
= Type
;
758 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
759 (*QueryResultSet
)->Data
.A
.IpAddress
= Address
;
761 (*QueryResultSet
)->pName
= (LPSTR
)DnsCToW(HostWithDomainName
);
763 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName
);
764 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
767 if ((Options
& DNS_QUERY_NO_WIRE_QUERY
) != 0)
769 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
770 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
771 return ERROR_FILE_NOT_FOUND
;
774 adns_error
= adns_init(&astate
, adns_if_noenv
| adns_if_noerrprint
| adns_if_noserverwarn
, 0);
775 if (adns_error
!= adns_s_ok
)
777 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
778 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
779 return DnsIntTranslateAdnsToDNS_STATUS(adns_error
);
781 for (pip
= &(network_info
->DnsServerList
); pip
; pip
= pip
->Next
)
783 addr
.s_addr
= inet_addr(pip
->IpAddress
.String
);
784 if ((addr
.s_addr
!= INADDR_ANY
) && (addr
.s_addr
!= INADDR_NONE
))
785 adns_addserver(astate
, addr
);
787 if (network_info
->DomainName
[0])
789 adns_ccf_search(astate
, "LOCALDOMAIN", -1, network_info
->DomainName
);
791 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info
);
795 for (i
= 0; i
< Servers
->AddrCount
; i
++)
797 adns_addserver(astate
, *((struct in_addr
*)&Servers
->AddrArray
[i
]));
802 * adns doesn't resolve chained CNAME records (a CNAME which points to
803 * another CNAME pointing to another... pointing to an A record), according
804 * to a mailing list thread the authors believe that chained CNAME records
805 * are invalid and the DNS entries should be fixed. That's a nice academic
806 * standpoint, but there certainly are chained CNAME records out there,
807 * even some fairly major ones (at the time of this writing
808 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
809 * these fine, so we should too. So we loop here to try to resolve CNAME
810 * chains ourselves. Of course, there must be a limit to protect against
814 #define CNAME_LOOP_MAX 16
816 CurrentName
= AnsiName
;
818 for (CNameLoop
= 0; CNameLoop
< CNAME_LOOP_MAX
; CNameLoop
++)
820 adns_error
= adns_synchronous(astate
, CurrentName
, adns_r_addr
, quflags
, &answer
);
822 if (adns_error
!= adns_s_ok
)
826 if (CurrentName
!= AnsiName
)
827 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
829 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
830 return DnsIntTranslateAdnsToDNS_STATUS(adns_error
);
833 if (answer
&& answer
->rrs
.addr
)
835 if (CurrentName
!= AnsiName
)
836 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
838 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
839 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
841 if (NULL
== *QueryResultSet
)
844 return ERROR_OUTOFMEMORY
;
847 (*QueryResultSet
)->pNext
= NULL
;
848 (*QueryResultSet
)->wType
= Type
;
849 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
850 (*QueryResultSet
)->Data
.A
.IpAddress
= answer
->rrs
.addr
->addr
.inet
.sin_addr
.s_addr
;
854 (*QueryResultSet
)->pName
= (LPSTR
)xstrsave(Name
);
856 return (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
859 if (NULL
== answer
|| adns_s_prohibitedcname
!= answer
->status
|| NULL
== answer
->cname
)
863 if (CurrentName
!= AnsiName
)
864 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
866 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
867 return ERROR_FILE_NOT_FOUND
;
870 if (CurrentName
!= AnsiName
)
871 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
873 CurrentName
= (LPSTR
)xstrsaveA(answer
->cname
);
877 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
879 return ERROR_OUTOFMEMORY
;
884 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName
);
885 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
886 return ERROR_FILE_NOT_FOUND
;
889 return ERROR_OUTOFMEMORY
; /* XXX arty: find a better error code. */
894 DnsQuery_UTF8(LPCSTR Name
,
898 PDNS_RECORD
*QueryResultSet
,
902 return ERROR_OUTOFMEMORY
;
906 DnsIntFreeRecordList(PDNS_RECORD ToDelete
)
909 PDNS_RECORD next
= 0;
914 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->pName
);
916 switch(ToDelete
->wType
)
926 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.PTR
.pNameHost
);
931 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.MX
.pNameExchange
);
935 for(i
= 0; i
< ToDelete
->Data
.TXT
.dwStringCount
; i
++)
936 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
[i
]);
938 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
);
942 next
= ToDelete
->pNext
;
943 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
);