[USB]
[reactos.git] / reactos / dll / win32 / dnsapi / dnsapi / query.c
1 /*
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
7 * UPDATE HISTORY:
8 * 12/15/03 -- Created
9 */
10
11 #include "precomp.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
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
19 * functions.
20 *
21 * Name -- The DNS object to be queried.
22 * Type -- The type of records to be returned. These are
23 * listed in windns.h
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
27 * windns.h
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.
32 */
33
34 char
35 *xstrsave(const char *str)
36 {
37 char *p;
38
39 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, strlen(str) + 1);
40
41 if(p)
42 strcpy(p, str);
43
44 return p;
45 }
46
47 DNS_STATUS WINAPI
48 DnsQuery_A(LPCSTR Name,
49 WORD Type,
50 DWORD Options,
51 PIP4_ARRAY Servers,
52 PDNS_RECORD *QueryResultSet,
53 PVOID *Reserved)
54 {
55 adns_state astate;
56 int quflags = 0;
57 int adns_error;
58 adns_answer *answer;
59 LPSTR CurrentName;
60 unsigned i, CNameLoop;
61
62 *QueryResultSet = 0;
63
64 switch(Type)
65 {
66 case DNS_TYPE_A:
67 adns_error = adns_init(&astate, adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn, 0);
68
69 if(adns_error != adns_s_ok)
70 return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
71
72 if (Servers)
73 {
74 for(i = 0; i < Servers->AddrCount; i++)
75 {
76 adns_addserver(astate, *((struct in_addr *)&Servers->AddrArray[i]));
77 }
78 }
79
80 /*
81 * adns doesn't resolve chained CNAME records (a CNAME which points to
82 * another CNAME pointing to another... pointing to an A record), according
83 * to a mailing list thread the authors believe that chained CNAME records
84 * are invalid and the DNS entries should be fixed. That's a nice academic
85 * standpoint, but there certainly are chained CNAME records out there,
86 * even some fairly major ones (at the time of this writing
87 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
88 * these fine, so we should too. So we loop here to try to resolve CNAME
89 * chains ourselves. Of course, there must be a limit to protect against
90 * CNAME loops.
91 */
92
93 #define CNAME_LOOP_MAX 16
94
95 CurrentName = (LPSTR) Name;
96
97 for (CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++)
98 {
99 adns_error = adns_synchronous(astate, CurrentName, adns_r_addr, quflags, &answer);
100
101 if(adns_error != adns_s_ok)
102 {
103 adns_finish(astate);
104
105 if (CurrentName != Name)
106 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
107
108 return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
109 }
110
111 if(answer && answer->rrs.addr)
112 {
113 if (CurrentName != Name)
114 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
115
116 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
117
118 if (NULL == *QueryResultSet)
119 {
120 adns_finish( astate );
121 return ERROR_OUTOFMEMORY;
122 }
123
124 (*QueryResultSet)->pNext = NULL;
125 (*QueryResultSet)->wType = Type;
126 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
127 (*QueryResultSet)->Data.A.IpAddress = answer->rrs.addr->addr.inet.sin_addr.s_addr;
128
129 adns_finish(astate);
130
131 (*QueryResultSet)->pName = xstrsave( Name );
132
133 return NULL != (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
134 }
135
136 if (NULL == answer || adns_s_prohibitedcname != answer->status || NULL == answer->cname)
137 {
138 adns_finish(astate);
139
140 if (CurrentName != Name)
141 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
142
143 return ERROR_FILE_NOT_FOUND;
144 }
145
146 if (CurrentName != Name)
147 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
148
149 CurrentName = xstrsave(answer->cname);
150
151 if (!CurrentName)
152 {
153 adns_finish(astate);
154 return ERROR_OUTOFMEMORY;
155 }
156 }
157
158 adns_finish(astate);
159 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
160 return ERROR_FILE_NOT_FOUND;
161
162 default:
163 return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */
164 }
165 }
166
167 static PCHAR
168 DnsWToC(const WCHAR *WideString)
169 {
170 int chars = wcstombs(NULL, WideString, 0);
171 PCHAR out = RtlAllocateHeap(RtlGetProcessHeap(), 0, chars + 1);
172
173 wcstombs(out, WideString, chars + 1);
174
175 return out;
176 }
177
178 static PWCHAR
179 DnsCToW(const CHAR *NarrowString)
180 {
181 int chars = mbstowcs(NULL, NarrowString, 0);
182 PWCHAR out = RtlAllocateHeap(RtlGetProcessHeap(), 0, (chars + 1) * sizeof(WCHAR));
183
184 mbstowcs(out, NarrowString, chars + 1);
185
186 return out;
187 }
188
189 DNS_STATUS WINAPI
190 DnsQuery_W(LPCWSTR Name,
191 WORD Type,
192 DWORD Options,
193 PIP4_ARRAY Servers,
194 PDNS_RECORD *QueryResultSet,
195 PVOID *Reserved)
196 {
197 UINT i;
198 PCHAR Buffer;
199 DNS_STATUS Status;
200 PDNS_RECORD QueryResultWide;
201 PDNS_RECORD ConvertedRecord = 0, LastRecord = 0;
202
203 Buffer = DnsWToC(Name);
204
205 Status = DnsQuery_A(Buffer, Type, Options, Servers, &QueryResultWide, Reserved);
206
207 while(Status == ERROR_SUCCESS && QueryResultWide)
208 {
209 switch(QueryResultWide->wType)
210 {
211 case DNS_TYPE_A:
212 case DNS_TYPE_WKS:
213 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
214 ConvertedRecord->pName = (PCHAR)DnsCToW(QueryResultWide->pName);
215 ConvertedRecord->wType = QueryResultWide->wType;
216 ConvertedRecord->wDataLength = QueryResultWide->wDataLength;
217 memcpy(ConvertedRecord, QueryResultWide, QueryResultWide->wDataLength);
218 break;
219
220 case DNS_TYPE_CNAME:
221 case DNS_TYPE_PTR:
222 case DNS_TYPE_NS:
223 case DNS_TYPE_MB:
224 case DNS_TYPE_MD:
225 case DNS_TYPE_MF:
226 case DNS_TYPE_MG:
227 case DNS_TYPE_MR:
228 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
229 ConvertedRecord->pName = (PCHAR)DnsCToW(QueryResultWide->pName);
230 ConvertedRecord->wType = QueryResultWide->wType;
231 ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATA);
232 ConvertedRecord->Data.PTR.pNameHost = (PCHAR)DnsCToW(QueryResultWide->Data.PTR.pNameHost);
233 break;
234
235 case DNS_TYPE_MINFO:
236 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
237 ConvertedRecord->pName = (PCHAR)DnsCToW(QueryResultWide->pName);
238 ConvertedRecord->wType = QueryResultWide->wType;
239 ConvertedRecord->wDataLength = sizeof(DNS_MINFO_DATA);
240 ConvertedRecord->Data.MINFO.pNameMailbox = (PCHAR)DnsCToW(QueryResultWide->Data.MINFO.pNameMailbox);
241 ConvertedRecord->Data.MINFO.pNameErrorsMailbox = (PCHAR)DnsCToW(QueryResultWide->Data.MINFO.pNameErrorsMailbox);
242 break;
243
244 case DNS_TYPE_MX:
245 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
246 ConvertedRecord->pName = (PCHAR)DnsCToW(QueryResultWide->pName);
247 ConvertedRecord->wType = QueryResultWide->wType;
248 ConvertedRecord->wDataLength = sizeof(DNS_MX_DATA);
249 ConvertedRecord->Data.MX.pNameExchange = (PCHAR)DnsCToW( QueryResultWide->Data.MX.pNameExchange);
250 ConvertedRecord->Data.MX.wPreference = QueryResultWide->Data.MX.wPreference;
251 break;
252
253 case DNS_TYPE_HINFO:
254 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATA) + QueryResultWide->Data.TXT.dwStringCount);
255 ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
256 ConvertedRecord->wType = QueryResultWide->wType;
257 ConvertedRecord->wDataLength = sizeof(DNS_TXT_DATA) + (sizeof(PWCHAR) * QueryResultWide->Data.TXT.dwStringCount);
258 ConvertedRecord->Data.TXT.dwStringCount = QueryResultWide->Data.TXT.dwStringCount;
259
260 for(i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++)
261 ConvertedRecord->Data.TXT.pStringArray[i] = (PCHAR)DnsCToW(QueryResultWide->Data.TXT.pStringArray[i]);
262
263 break;
264
265 case DNS_TYPE_NULL:
266 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount);
267 ConvertedRecord->pName = (PCHAR)DnsCToW(QueryResultWide->pName);
268 ConvertedRecord->wType = QueryResultWide->wType;
269 ConvertedRecord->wDataLength = sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount;
270 ConvertedRecord->Data.Null.dwByteCount = QueryResultWide->Data.Null.dwByteCount;
271 memcpy(&ConvertedRecord->Data.Null.Data, &QueryResultWide->Data.Null.Data, QueryResultWide->Data.Null.dwByteCount);
272 break;
273 }
274
275 if(LastRecord)
276 {
277 LastRecord->pNext = ConvertedRecord;
278 LastRecord = LastRecord->pNext;
279 }
280 else
281 {
282 LastRecord = *QueryResultSet = ConvertedRecord;
283 }
284 }
285
286 LastRecord->pNext = 0;
287
288 /* The name */
289 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
290
291 return Status;
292 }
293
294 DNS_STATUS WINAPI
295 DnsQuery_UTF8(LPCSTR Name,
296 WORD Type,
297 DWORD Options,
298 PIP4_ARRAY Servers,
299 PDNS_RECORD *QueryResultSet,
300 PVOID *Reserved)
301 {
302 UNIMPLEMENTED;
303 return ERROR_OUTOFMEMORY;
304 }
305
306 void
307 DnsIntFreeRecordList(PDNS_RECORD ToDelete)
308 {
309 UINT i;
310 PDNS_RECORD next = 0;
311
312 while(ToDelete)
313 {
314 if(ToDelete->pName)
315 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->pName);
316
317 switch(ToDelete->wType)
318 {
319 case DNS_TYPE_CNAME:
320 case DNS_TYPE_PTR:
321 case DNS_TYPE_NS:
322 case DNS_TYPE_MB:
323 case DNS_TYPE_MD:
324 case DNS_TYPE_MF:
325 case DNS_TYPE_MG:
326 case DNS_TYPE_MR:
327 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.PTR.pNameHost);
328 break;
329
330 case DNS_TYPE_MINFO:
331 case DNS_TYPE_MX:
332 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.MX.pNameExchange);
333 break;
334
335 case DNS_TYPE_HINFO:
336 for(i = 0; i < ToDelete->Data.TXT.dwStringCount; i++)
337 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray[i]);
338
339 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray);
340 break;
341 }
342
343 next = ToDelete->pNext;
344 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete);
345 ToDelete = next;
346 }
347 }