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
,
67 if( adns_error
!= adns_s_ok
) {
68 return DnsIntTranslateAdnsToDNS_STATUS( adns_error
);
72 * adns doesn't resolve chained CNAME records (a CNAME which points to
73 * another CNAME pointing to another... pointing to an A record), according
74 * to a mailing list thread the authors believe that chained CNAME records
75 * are invalid and the DNS entries should be fixed. That's a nice academic
76 * standpoint, but there certainly are chained CNAME records out there,
77 * even some fairly major ones (at the time of this writing
78 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
79 * these fine, so we should too. So we loop here to try to resolve CNAME
80 * chains ourselves. Of course, there must be a limit to protect against
84 #define CNAME_LOOP_MAX 16
86 CurrentName
= (LPSTR
) Name
;
87 for ( CNameLoop
= 0; CNameLoop
< CNAME_LOOP_MAX
; CNameLoop
++ ) {
88 adns_error
= adns_synchronous( astate
,
94 if( adns_error
!= adns_s_ok
) {
95 adns_finish( astate
);
96 if ( CurrentName
!= Name
) {
97 RtlFreeHeap( CurrentName
, 0, GetProcessHeap() );
99 return DnsIntTranslateAdnsToDNS_STATUS( adns_error
);
102 if( answer
&& answer
->rrs
.addr
) {
103 if ( CurrentName
!= Name
) {
104 RtlFreeHeap( CurrentName
, 0, GetProcessHeap() );
107 (PDNS_RECORD
)RtlAllocateHeap( RtlGetProcessHeap(), 0,
108 sizeof( DNS_RECORD
) );
109 if ( NULL
== *QueryResultSet
) {
110 adns_finish( astate
);
111 return ERROR_OUTOFMEMORY
;
113 (*QueryResultSet
)->pNext
= NULL
;
114 (*QueryResultSet
)->wType
= Type
;
115 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
116 (*QueryResultSet
)->Data
.A
.IpAddress
=
117 answer
->rrs
.addr
->addr
.inet
.sin_addr
.s_addr
;
118 adns_finish( astate
);
119 (*QueryResultSet
)->pName
= xstrsave( Name
);
120 return NULL
!= (*QueryResultSet
)->pName
? ERROR_SUCCESS
:
123 if ( NULL
== answer
|| adns_s_prohibitedcname
!= answer
->status
||
124 NULL
== answer
->cname
) {
125 adns_finish( astate
);
126 if ( CurrentName
!= Name
) {
127 RtlFreeHeap( CurrentName
, 0, GetProcessHeap() );
129 return ERROR_FILE_NOT_FOUND
;
131 if ( CurrentName
!= Name
) {
132 RtlFreeHeap( CurrentName
, 0, GetProcessHeap() );
134 CurrentName
= xstrsave( answer
->cname
);
135 if ( NULL
== CurrentName
) {
136 adns_finish( astate
);
137 return ERROR_OUTOFMEMORY
;
140 adns_finish( astate
);
141 RtlFreeHeap( CurrentName
, 0, GetProcessHeap() );
142 return ERROR_FILE_NOT_FOUND
;
144 return ERROR_OUTOFMEMORY
; /* XXX arty: find a better error code. */
148 static PCHAR
DnsWToC( const WCHAR
*WideString
) {
149 int chars
= wcstombs( NULL
, WideString
, 0 );
150 PCHAR out
= RtlAllocateHeap( RtlGetProcessHeap(), 0, chars
+ 1 );
151 wcstombs( out
, WideString
, chars
+ 1 );
155 static PWCHAR
DnsCToW( const CHAR
*NarrowString
) {
156 int chars
= mbstowcs( NULL
, NarrowString
, 0 );
157 PWCHAR out
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
158 (chars
+ 1) * sizeof(WCHAR
) );
159 mbstowcs( out
, NarrowString
, chars
+ 1 );
163 DNS_STATUS WINAPI DnsQuery_W
168 PDNS_RECORD
*QueryResultSet
,
173 PDNS_RECORD QueryResultWide
;
174 PDNS_RECORD ConvertedRecord
= 0, LastRecord
= 0;
176 Buffer
= DnsWToC( Name
);
178 Status
= DnsQuery_A( Buffer
, Type
, Options
, Servers
, &QueryResultWide
,
181 while( Status
== ERROR_SUCCESS
&& QueryResultWide
) {
182 switch( QueryResultWide
->wType
) {
189 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
190 sizeof(DNS_RECORD
) );
191 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
192 ConvertedRecord
->wType
= QueryResultWide
->wType
;
193 ConvertedRecord
->wDataLength
= QueryResultWide
->wDataLength
;
194 memcpy( ConvertedRecord
, QueryResultWide
,
195 QueryResultWide
->wDataLength
);
206 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
207 sizeof(DNS_RECORD
) );
208 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
209 ConvertedRecord
->wType
= QueryResultWide
->wType
;
210 ConvertedRecord
->wDataLength
= sizeof(DNS_PTR_DATA
);
211 ConvertedRecord
->Data
.PTR
.pNameHost
=
212 (PCHAR
)DnsCToW( QueryResultWide
->Data
.PTR
.pNameHost
);
218 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
219 sizeof(DNS_RECORD
) );
220 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
221 ConvertedRecord
->wType
= QueryResultWide
->wType
;
222 ConvertedRecord
->wDataLength
= sizeof(DNS_MINFO_DATA
);
223 ConvertedRecord
->Data
.MINFO
.pNameMailbox
=
224 (PCHAR
)DnsCToW( QueryResultWide
->Data
.MINFO
.pNameMailbox
);
225 ConvertedRecord
->Data
.MINFO
.pNameErrorsMailbox
=
226 (PCHAR
)DnsCToW( QueryResultWide
->Data
.MINFO
.pNameErrorsMailbox
);
234 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
235 sizeof(DNS_RECORD
) );
236 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
237 ConvertedRecord
->wType
= QueryResultWide
->wType
;
238 ConvertedRecord
->wDataLength
= sizeof(DNS_MX_DATA
);
239 ConvertedRecord
->Data
.MX
.pNameExchange
=
240 (PCHAR
)DnsCToW( QueryResultWide
->Data
.MX
.pNameExchange
);
241 ConvertedRecord
->Data
.MX
.wPreference
=
242 QueryResultWide
->Data
.MX
.wPreference
;
250 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
251 sizeof(DNS_TXT_DATA
) +
253 Data
.TXT
.dwStringCount
);
254 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
255 ConvertedRecord
->wType
= QueryResultWide
->wType
;
256 ConvertedRecord
->wDataLength
=
257 sizeof(DNS_TXT_DATA
) +
258 (sizeof(PWCHAR
) * QueryResultWide
->Data
.TXT
.dwStringCount
);
259 ConvertedRecord
->Data
.TXT
.dwStringCount
=
260 QueryResultWide
->Data
.TXT
.dwStringCount
;
261 for( i
= 0; i
< ConvertedRecord
->Data
.TXT
.dwStringCount
; i
++ ) {
262 ConvertedRecord
->Data
.TXT
.pStringArray
[i
] =
263 (PCHAR
)DnsCToW( QueryResultWide
->Data
.TXT
.pStringArray
[i
] );
268 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
269 sizeof(DNS_NULL_DATA
) +
271 Data
.Null
.dwByteCount
);
272 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
273 ConvertedRecord
->wType
= QueryResultWide
->wType
;
274 ConvertedRecord
->wDataLength
=
275 sizeof(DNS_NULL_DATA
) + QueryResultWide
->Data
.Null
.dwByteCount
;
276 ConvertedRecord
->Data
.Null
.dwByteCount
=
277 QueryResultWide
->Data
.Null
.dwByteCount
;
278 memcpy( &ConvertedRecord
->Data
.Null
.Data
,
279 &QueryResultWide
->Data
.Null
.Data
,
280 QueryResultWide
->Data
.Null
.dwByteCount
);
285 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
286 sizeof(DNS_RECORDA
) );
287 ConvertedRecord
->pName
= DnsCToW( QueryResultWide
->pName
);
288 ConvertedRecord
->wType
= QueryResultWide
->wType
;
289 ConvertedRecord
->wDataLength
= sizeof(DNS_SIG_DATAA
);
290 memcpy( &ConvertedRecord
->Data
.SIG
,
291 &QueryResultWide
->Data
.SIG
,
292 sizeof(QueryResultWide
->Data
.SIG
) );
293 ConvertedRecord
->Data
.SIG
.pNameSigner
=
294 DnsCToW( QueryResultWide
->Data
.SIG
.pNameSigner
);
298 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
299 sizeof(DNS_RECORDA
) );
300 ConvertedRecord
->pName
= DnsCToW( QueryResultWide
->pName
);
301 ConvertedRecord
->wType
= QueryResultWide
->wType
;
302 ConvertedRecord
->wDataLength
= sizeof(DNS_NXT_DATAA
);
303 memcpy( &ConvertedRecord
->Data
.NXT
,
304 &QueryResultWide
->Data
.NXT
,
305 sizeof(QueryResultWide
->Data
.NXT
) );
306 ConvertedRecord
->Data
.NXT
.pNameNext
=
307 DnsCToW( QueryResultWide
->Data
.NXT
.pNameNext
);
311 ConvertedRecord
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
312 sizeof(DNS_RECORDA
) );
313 ConvertedRecord
->pName
= DnsCToW( QueryResultWide
->pName
);
314 ConvertedRecord
->wType
= QueryResultWide
->wType
;
315 ConvertedRecord
->wDataLength
= sizeof(DNS_SRV_DATAA
);
316 memcpy( &ConvertedRecord
->Data
.SRV
,
317 &QueryResultWide
->Data
.SRV
,
318 sizeof(QueryResultWide
->Data
.SRV
) );
319 ConvertedRecord
->Data
.SRV
.pNameTarget
=
320 DnsCToW( QueryResultWide
->Data
.SRV
.pNameTarget
);
326 LastRecord
->pNext
= ConvertedRecord
;
327 LastRecord
= LastRecord
->pNext
;
329 LastRecord
= *QueryResultSet
= ConvertedRecord
;
333 LastRecord
->pNext
= 0;
336 RtlFreeHeap( RtlGetProcessHeap(), 0, Buffer
);
341 DNS_STATUS WINAPI DnsQuery_UTF8
346 PDNS_RECORD
*QueryResultSet
,
348 return DnsQuery_UTF8( Name
, Type
, Options
, Servers
, QueryResultSet
,
352 void DnsIntFreeRecordList( PDNS_RECORD ToDelete
) {
354 PDNS_RECORD next
= 0;
357 if( ToDelete
->pName
)
358 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->pName
);
359 switch( ToDelete
->wType
) {
368 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->Data
.PTR
.pNameHost
);
373 RtlFreeHeap( RtlGetProcessHeap(), 0,
374 ToDelete
->Data
.MINFO
.pNameMailbox
);
375 RtlFreeHeap( RtlGetProcessHeap(), 0,
376 ToDelete
->Data
.MINFO
.pNameErrorsMailbox
);
383 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->Data
.MX
.pNameExchange
);
391 for( i
= 0; i
< ToDelete
->Data
.TXT
.dwStringCount
; i
++ ) {
392 RtlFreeHeap( RtlGetProcessHeap(), 0,
393 ToDelete
->Data
.TXT
.pStringArray
[i
] );
395 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
);
400 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->Data
.SIG
.pNameSigner
);
404 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->Data
.NXT
.pNameNext
);
408 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
->Data
.SRV
.pNameTarget
);
413 next
= ToDelete
->pNext
;
414 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete
);