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.
35 *xstrsave(const char *str
)
39 p
= RtlAllocateHeap(RtlGetProcessHeap(), 0, strlen(str
) + 1);
48 DnsQuery_A(LPCSTR Name
,
52 PDNS_RECORD
*QueryResultSet
,
60 unsigned i
, CNameLoop
;
63 return ERROR_INVALID_PARAMETER
;
70 adns_error
= adns_init(&astate
, adns_if_noenv
| adns_if_noerrprint
| adns_if_noserverwarn
, 0);
72 if(adns_error
!= adns_s_ok
)
73 return DnsIntTranslateAdnsToDNS_STATUS(adns_error
);
77 for(i
= 0; i
< Servers
->AddrCount
; i
++)
79 adns_addserver(astate
, *((struct in_addr
*)&Servers
->AddrArray
[i
]));
84 * adns doesn't resolve chained CNAME records (a CNAME which points to
85 * another CNAME pointing to another... pointing to an A record), according
86 * to a mailing list thread the authors believe that chained CNAME records
87 * are invalid and the DNS entries should be fixed. That's a nice academic
88 * standpoint, but there certainly are chained CNAME records out there,
89 * even some fairly major ones (at the time of this writing
90 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
91 * these fine, so we should too. So we loop here to try to resolve CNAME
92 * chains ourselves. Of course, there must be a limit to protect against
96 #define CNAME_LOOP_MAX 16
98 CurrentName
= (LPSTR
) Name
;
100 for (CNameLoop
= 0; CNameLoop
< CNAME_LOOP_MAX
; CNameLoop
++)
102 adns_error
= adns_synchronous(astate
, CurrentName
, adns_r_addr
, quflags
, &answer
);
104 if(adns_error
!= adns_s_ok
)
108 if (CurrentName
!= Name
)
109 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
111 return DnsIntTranslateAdnsToDNS_STATUS(adns_error
);
114 if(answer
&& answer
->rrs
.addr
)
116 if (CurrentName
!= Name
)
117 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
119 *QueryResultSet
= (PDNS_RECORD
)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
121 if (NULL
== *QueryResultSet
)
123 adns_finish( astate
);
124 return ERROR_OUTOFMEMORY
;
127 (*QueryResultSet
)->pNext
= NULL
;
128 (*QueryResultSet
)->wType
= Type
;
129 (*QueryResultSet
)->wDataLength
= sizeof(DNS_A_DATA
);
130 (*QueryResultSet
)->Data
.A
.IpAddress
= answer
->rrs
.addr
->addr
.inet
.sin_addr
.s_addr
;
134 (*QueryResultSet
)->pName
= xstrsave( Name
);
136 return NULL
!= (*QueryResultSet
)->pName
? ERROR_SUCCESS
: ERROR_OUTOFMEMORY
;
139 if (NULL
== answer
|| adns_s_prohibitedcname
!= answer
->status
|| NULL
== answer
->cname
)
143 if (CurrentName
!= Name
)
144 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
146 return ERROR_FILE_NOT_FOUND
;
149 if (CurrentName
!= Name
)
150 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
152 CurrentName
= xstrsave(answer
->cname
);
157 return ERROR_OUTOFMEMORY
;
162 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName
);
163 return ERROR_FILE_NOT_FOUND
;
166 return ERROR_OUTOFMEMORY
; /* XXX arty: find a better error code. */
171 DnsWToC(const WCHAR
*WideString
)
173 int chars
= wcstombs(NULL
, WideString
, 0);
174 PCHAR out
= RtlAllocateHeap(RtlGetProcessHeap(), 0, chars
+ 1);
176 wcstombs(out
, WideString
, chars
+ 1);
182 DnsCToW(const CHAR
*NarrowString
)
184 int chars
= mbstowcs(NULL
, NarrowString
, 0);
185 PWCHAR out
= RtlAllocateHeap(RtlGetProcessHeap(), 0, (chars
+ 1) * sizeof(WCHAR
));
187 mbstowcs(out
, NarrowString
, chars
+ 1);
193 DnsQuery_W(LPCWSTR Name
,
197 PDNS_RECORD
*QueryResultSet
,
203 PDNS_RECORD QueryResultWide
;
204 PDNS_RECORD ConvertedRecord
= 0, LastRecord
= 0;
207 return ERROR_INVALID_PARAMETER
;
209 Buffer
= DnsWToC(Name
);
211 Status
= DnsQuery_A(Buffer
, Type
, Options
, Servers
, &QueryResultWide
, Reserved
);
213 while(Status
== ERROR_SUCCESS
&& QueryResultWide
)
215 switch(QueryResultWide
->wType
)
219 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
220 ConvertedRecord
->pName
= (PCHAR
)DnsCToW(QueryResultWide
->pName
);
221 ConvertedRecord
->wType
= QueryResultWide
->wType
;
222 ConvertedRecord
->wDataLength
= QueryResultWide
->wDataLength
;
223 memcpy(ConvertedRecord
, QueryResultWide
, QueryResultWide
->wDataLength
);
234 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
235 ConvertedRecord
->pName
= (PCHAR
)DnsCToW(QueryResultWide
->pName
);
236 ConvertedRecord
->wType
= QueryResultWide
->wType
;
237 ConvertedRecord
->wDataLength
= sizeof(DNS_PTR_DATA
);
238 ConvertedRecord
->Data
.PTR
.pNameHost
= (PCHAR
)DnsCToW(QueryResultWide
->Data
.PTR
.pNameHost
);
242 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
243 ConvertedRecord
->pName
= (PCHAR
)DnsCToW(QueryResultWide
->pName
);
244 ConvertedRecord
->wType
= QueryResultWide
->wType
;
245 ConvertedRecord
->wDataLength
= sizeof(DNS_MINFO_DATA
);
246 ConvertedRecord
->Data
.MINFO
.pNameMailbox
= (PCHAR
)DnsCToW(QueryResultWide
->Data
.MINFO
.pNameMailbox
);
247 ConvertedRecord
->Data
.MINFO
.pNameErrorsMailbox
= (PCHAR
)DnsCToW(QueryResultWide
->Data
.MINFO
.pNameErrorsMailbox
);
251 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD
));
252 ConvertedRecord
->pName
= (PCHAR
)DnsCToW(QueryResultWide
->pName
);
253 ConvertedRecord
->wType
= QueryResultWide
->wType
;
254 ConvertedRecord
->wDataLength
= sizeof(DNS_MX_DATA
);
255 ConvertedRecord
->Data
.MX
.pNameExchange
= (PCHAR
)DnsCToW( QueryResultWide
->Data
.MX
.pNameExchange
);
256 ConvertedRecord
->Data
.MX
.wPreference
= QueryResultWide
->Data
.MX
.wPreference
;
260 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATA
) + QueryResultWide
->Data
.TXT
.dwStringCount
);
261 ConvertedRecord
->pName
= (PCHAR
)DnsCToW( QueryResultWide
->pName
);
262 ConvertedRecord
->wType
= QueryResultWide
->wType
;
263 ConvertedRecord
->wDataLength
= sizeof(DNS_TXT_DATA
) + (sizeof(PWCHAR
) * QueryResultWide
->Data
.TXT
.dwStringCount
);
264 ConvertedRecord
->Data
.TXT
.dwStringCount
= QueryResultWide
->Data
.TXT
.dwStringCount
;
266 for(i
= 0; i
< ConvertedRecord
->Data
.TXT
.dwStringCount
; i
++)
267 ConvertedRecord
->Data
.TXT
.pStringArray
[i
] = (PCHAR
)DnsCToW(QueryResultWide
->Data
.TXT
.pStringArray
[i
]);
272 ConvertedRecord
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_NULL_DATA
) + QueryResultWide
->Data
.Null
.dwByteCount
);
273 ConvertedRecord
->pName
= (PCHAR
)DnsCToW(QueryResultWide
->pName
);
274 ConvertedRecord
->wType
= QueryResultWide
->wType
;
275 ConvertedRecord
->wDataLength
= sizeof(DNS_NULL_DATA
) + QueryResultWide
->Data
.Null
.dwByteCount
;
276 ConvertedRecord
->Data
.Null
.dwByteCount
= QueryResultWide
->Data
.Null
.dwByteCount
;
277 memcpy(&ConvertedRecord
->Data
.Null
.Data
, &QueryResultWide
->Data
.Null
.Data
, QueryResultWide
->Data
.Null
.dwByteCount
);
283 LastRecord
->pNext
= ConvertedRecord
;
284 LastRecord
= LastRecord
->pNext
;
288 LastRecord
= *QueryResultSet
= ConvertedRecord
;
293 LastRecord
->pNext
= 0;
296 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
302 DnsQuery_UTF8(LPCSTR Name
,
306 PDNS_RECORD
*QueryResultSet
,
310 return ERROR_OUTOFMEMORY
;
314 DnsIntFreeRecordList(PDNS_RECORD ToDelete
)
317 PDNS_RECORD next
= 0;
322 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->pName
);
324 switch(ToDelete
->wType
)
334 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.PTR
.pNameHost
);
339 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.MX
.pNameExchange
);
343 for(i
= 0; i
< ToDelete
->Data
.TXT
.dwStringCount
; i
++)
344 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
[i
]);
346 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
->Data
.TXT
.pStringArray
);
350 next
= ToDelete
->pNext
;
351 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete
);