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
16 /* DnsQuery ****************************
17 * Begin a DNS query, and allow the result to be placed in the application
18 * supplied result pointer. The result can be manipulated with the record
21 * Name -- The DNS object to be queried.
22 * Type -- The type of records to be returned. These are
24 * Options -- Query options. DNS_QUERY_STANDARD is the base
25 * state, and every other option takes precedence.
26 * multiple options can be combined. Listed in
28 * Servers -- List of alternate servers (optional)
29 * QueryResultSet -- Pointer to the result pointer that will be filled
30 * when the response is available.
31 * Reserved -- Response as it appears on the wire. Optional.
34 char *xstrsave(const char *str
) {
37 p
= RtlAllocateHeap( RtlGetProcessHeap(), 0, strlen(str
)+1 );
44 DNS_STATUS WINAPI DnsQuery_A
49 PDNS_RECORD
*QueryResultSet
,
62 adns_error
= adns_init( &astate
,
65 adns_if_noserverwarn
|
66 (Servers
? adns_if_noserver
: 0),
69 if( adns_error
!= adns_s_ok
) {
70 return DnsIntTranslateAdnsToDNS_STATUS( adns_error
);
74 for( i
= 0; i
< Servers
->AddrCount
; i
++ ) {
75 adns_addserver( astate
, *((struct in_addr
*)&Servers
->AddrArray
[i
]) );
80 * adns doesn't resolve chained CNAME records (a CNAME which points to
81 * another CNAME pointing to another... pointing to an A record), according
82 * to a mailing list thread the authors believe that chained CNAME records
83 * are invalid and the DNS entries should be fixed. That's a nice academic
84 * standpoint, but there certainly are chained CNAME records out there,
85 * even some fairly major ones (at the time of this writing
86 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
87 * these fine, so we should too. So we loop here to try to resolve CNAME
88 * chains ourselves. Of course, there must be a limit to protect against
92 #define CNAME_LOOP_MAX 16
94 CurrentName
= (LPSTR
) Name
;
95 for ( CNameLoop
= 0; CNameLoop
< CNAME_LOOP_MAX
; CNameLoop
++ ) {
96 adns_error
= adns_synchronous( astate
,
102 if( adns_error
!= adns_s_ok
) {
103 adns_finish( astate
);
104 if ( CurrentName
!= Name
) {
105 RtlFreeHeap( RtlGetProcessHeap(), 0, CurrentName
);
107 return DnsIntTranslateAdnsToDNS_STATUS( adns_error
);
110 if( answer
&& answer
->rrs
.addr
) {
111 if ( CurrentName
!= Name
) {
112 RtlFreeHeap( RtlGetProcessHeap(), 0, CurrentName
);
115 (PDNS_RECORD
)RtlAllocateHeap( RtlGetProcessHeap(), 0,
116 sizeof( DNS_RECORD
) );
117 if ( NULL
== *QueryResultSet
) {
118 adns_finish( astate
);
119 return ERROR_OUTOFMEMORY
;
121 (*QueryResultSet
)->pNext
= NULL
;
122 (*QueryResultSet
)->wType
= Type
;
123 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
124 (*QueryResultSet
)->Data
.A
.IpAddress
=
125 answer
->rrs
.addr
->addr
.inet
.sin_addr
.s_addr
;
126 adns_finish( astate
);
127 (*QueryResultSet
)->pName
= xstrsave( Name
);
128 return NULL
!= (*QueryResultSet
)->pName
? ERROR_SUCCESS
:
131 if ( NULL
== answer
|| adns_s_prohibitedcname
!= answer
->status
||
132 NULL
== answer
->cname
) {
133 adns_finish( astate
);
134 if ( CurrentName
!= Name
) {
135 RtlFreeHeap( RtlGetProcessHeap(), 0, CurrentName
);
137 return ERROR_FILE_NOT_FOUND
;
139 if ( CurrentName
!= Name
) {
140 RtlFreeHeap( RtlGetProcessHeap(), 0, CurrentName
);
142 CurrentName
= xstrsave( answer
->cname
);
143 if ( NULL
== CurrentName
) {
144 adns_finish( astate
);
145 return ERROR_OUTOFMEMORY
;
148 adns_finish( astate
);
149 RtlFreeHeap( RtlGetProcessHeap(), 0, CurrentName
);
150 return ERROR_FILE_NOT_FOUND
;
152 return ERROR_OUTOFMEMORY
; /* XXX arty: find a better error code. */
156 static PCHAR
DnsWToC( const WCHAR
*WideString
) {
157 int chars
= wcstombs( NULL
, WideString
, 0 );
158 PCHAR out
= RtlAllocateHeap( RtlGetProcessHeap(), 0, chars
+ 1 );
159 wcstombs( out
, WideString
, chars
+ 1 );
163 static PWCHAR
DnsCToW( const CHAR
*NarrowString
) {
164 int chars
= mbstowcs( NULL
, NarrowString
, 0 );
165 PWCHAR out
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
166 (chars
+ 1) * sizeof(WCHAR
) );
167 mbstowcs( out
, NarrowString
, chars
+ 1 );
171 DNS_STATUS WINAPI DnsQuery_W
176 PDNS_RECORD
*QueryResultSet
,
181 PDNS_RECORD QueryResultWide
;
182 PDNS_RECORD ConvertedRecord
= 0, LastRecord
= 0;
184 Buffer
= DnsWToC( Name
);
186 Status
= DnsQuery_A( Buffer
, Type
, Options
, Servers
, &QueryResultWide
,
189 while( Status
== ERROR_SUCCESS
&& QueryResultWide
) {
190 switch( QueryResultWide
->wType
) {
193 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
194 sizeof(DNS_RECORD
) );
195 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
196 ConvertedRecord
->wType
= QueryResultWide
->wType
;
197 ConvertedRecord
->wDataLength
= QueryResultWide
->wDataLength
;
198 memcpy( ConvertedRecord
, QueryResultWide
,
199 QueryResultWide
->wDataLength
);
210 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
211 sizeof(DNS_RECORD
) );
212 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
213 ConvertedRecord
->wType
= QueryResultWide
->wType
;
214 ConvertedRecord
->wDataLength
= sizeof(DNS_PTR_DATA
);
215 ConvertedRecord
->Data
.PTR
.pNameHost
=
216 (PCHAR
)DnsCToW( QueryResultWide
->Data
.PTR
.pNameHost
);
219 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
220 sizeof(DNS_RECORD
) );
221 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
222 ConvertedRecord
->wType
= QueryResultWide
->wType
;
223 ConvertedRecord
->wDataLength
= sizeof(DNS_MINFO_DATA
);
224 ConvertedRecord
->Data
.MINFO
.pNameMailbox
=
225 (PCHAR
)DnsCToW( QueryResultWide
->Data
.MINFO
.pNameMailbox
);
226 ConvertedRecord
->Data
.MINFO
.pNameErrorsMailbox
=
227 (PCHAR
)DnsCToW( QueryResultWide
->Data
.MINFO
.pNameErrorsMailbox
);
231 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
232 sizeof(DNS_RECORD
) );
233 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
234 ConvertedRecord
->wType
= QueryResultWide
->wType
;
235 ConvertedRecord
->wDataLength
= sizeof(DNS_MX_DATA
);
236 ConvertedRecord
->Data
.MX
.pNameExchange
=
237 (PCHAR
)DnsCToW( QueryResultWide
->Data
.MX
.pNameExchange
);
238 ConvertedRecord
->Data
.MX
.wPreference
=
239 QueryResultWide
->Data
.MX
.wPreference
;
243 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
244 sizeof(DNS_TXT_DATA
) +
246 Data
.TXT
.dwStringCount
);
247 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
248 ConvertedRecord
->wType
= QueryResultWide
->wType
;
249 ConvertedRecord
->wDataLength
=
250 sizeof(DNS_TXT_DATA
) +
251 (sizeof(PWCHAR
) * QueryResultWide
->Data
.TXT
.dwStringCount
);
252 ConvertedRecord
->Data
.TXT
.dwStringCount
=
253 QueryResultWide
->Data
.TXT
.dwStringCount
;
254 for( i
= 0; i
< ConvertedRecord
->Data
.TXT
.dwStringCount
; i
++ ) {
255 ConvertedRecord
->Data
.TXT
.pStringArray
[i
] =
256 (PCHAR
)DnsCToW( QueryResultWide
->Data
.TXT
.pStringArray
[i
] );
261 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
262 sizeof(DNS_NULL_DATA
) +
264 Data
.Null
.dwByteCount
);
265 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
266 ConvertedRecord
->wType
= QueryResultWide
->wType
;
267 ConvertedRecord
->wDataLength
=
268 sizeof(DNS_NULL_DATA
) + QueryResultWide
->Data
.Null
.dwByteCount
;
269 ConvertedRecord
->Data
.Null
.dwByteCount
=
270 QueryResultWide
->Data
.Null
.dwByteCount
;
271 memcpy( &ConvertedRecord
->Data
.Null
.Data
,
272 &QueryResultWide
->Data
.Null
.Data
,
273 QueryResultWide
->Data
.Null
.dwByteCount
);
279 LastRecord
->pNext
= ConvertedRecord
;
280 LastRecord
= LastRecord
->pNext
;
282 LastRecord
= *QueryResultSet
= ConvertedRecord
;
286 LastRecord
->pNext
= 0;
289 RtlFreeHeap( RtlGetProcessHeap(), 0, Buffer
);
294 DNS_STATUS WINAPI DnsQuery_UTF8
299 PDNS_RECORD
*QueryResultSet
,
302 return ERROR_OUTOFMEMORY
;
305 void DnsIntFreeRecordList( PDNS_RECORD ToDelete
) {
307 PDNS_RECORD next
= 0;
310 if( ToDelete
->pName
)
311 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->pName
);
312 switch( ToDelete
->wType
) {
321 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->Data
.PTR
.pNameHost
);
325 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->Data
.MX
.pNameExchange
);
329 for( i
= 0; i
< ToDelete
->Data
.TXT
.dwStringCount
; i
++ ) {
330 RtlFreeHeap( RtlGetProcessHeap(), 0,
331 ToDelete
->Data
.TXT
.pStringArray
[i
] );
333 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
);
338 next
= ToDelete
->pNext
;
339 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
);