6f0ae2a91d51c49b1a67cdca06a8959e4f19e2de
[reactos.git] / reactos / lib / 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 <windows.h>
12 #include <WinError.h>
13 #include <windns.h>
14 #include <internal/windns.h>
15 #include <string.h>
16 #define NTOS_MODE_USER
17 #include <ntos.h>
18
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
22 * functions.
23 *
24 * Name -- The DNS object to be queried.
25 * Type -- The type of records to be returned. These are
26 * listed in windns.h
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
30 * windns.h
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.
35 */
36
37 char *xstrsave(const char *str) {
38 char *p;
39
40 p= RtlAllocateHeap( RtlGetProcessHeap(), 0, strlen(str)+1 );
41 strcpy(p,str);
42 return p;
43 }
44
45 DNS_STATUS WINAPI DnsQuery_A
46 ( LPCSTR Name,
47 WORD Type,
48 DWORD Options,
49 PIP4_ARRAY Servers,
50 PDNS_RECORD *QueryResultSet,
51 PVOID *Reserved ) {
52 adns_state astate;
53 int quflags = 0;
54 int adns_error;
55 adns_answer *answer;
56
57 *QueryResultSet = 0;
58
59 switch( Type ) {
60 case DNS_TYPE_A:
61 adns_error = adns_init( &astate,
62 adns_if_noenv |
63 adns_if_noerrprint |
64 adns_if_noserverwarn,
65 0 );
66 if( adns_error != adns_s_ok ) {
67 adns_finish( astate );
68 return DnsIntTranslateAdnsToDNS_STATUS( adns_error );
69 }
70
71 adns_error = adns_synchronous( astate,
72 Name,
73 adns_r_addr,
74 quflags,
75 &answer );
76
77 if( adns_error != adns_s_ok ) {
78 adns_finish( astate );
79 return DnsIntTranslateAdnsToDNS_STATUS( adns_error );
80 }
81
82 if( answer && answer->rrs.addr ) {
83 *QueryResultSet =
84 (PDNS_RECORD)RtlAllocateHeap( RtlGetProcessHeap(), 0,
85 sizeof( DNS_RECORD ) );
86 (*QueryResultSet)->pNext = NULL;
87 (*QueryResultSet)->wType = Type;
88 (*QueryResultSet)->pName = xstrsave( Name );
89 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
90 (*QueryResultSet)->Data.A.IpAddress =
91 answer->rrs.addr->addr.inet.sin_addr.s_addr;
92 adns_finish( astate );
93 return ERROR_SUCCESS;
94 } else
95 return ERROR_FILE_NOT_FOUND;
96 default:
97 return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */
98 }
99 }
100
101 static PCHAR DnsWToC( const WCHAR *WideString ) {
102 int chars = wcstombs( NULL, WideString, 0 );
103 PCHAR out = RtlAllocateHeap( RtlGetProcessHeap(), 0, chars + 1 );
104 wcstombs( out, WideString, chars + 1 );
105 return out;
106 }
107
108 static PWCHAR DnsCToW( const CHAR *NarrowString ) {
109 int chars = mbstowcs( NULL, NarrowString, 0 );
110 PWCHAR out = RtlAllocateHeap( RtlGetProcessHeap(), 0,
111 (chars + 1) * sizeof(WCHAR) );
112 mbstowcs( out, NarrowString, chars + 1 );
113 return out;
114 }
115
116 DNS_STATUS WINAPI DnsQuery_W
117 ( LPCWSTR Name,
118 WORD Type,
119 DWORD Options,
120 PIP4_ARRAY Servers,
121 PDNS_RECORD *QueryResultSet,
122 PVOID *Reserved ) {
123 int i;
124 PCHAR Buffer;
125 DNS_STATUS Status;
126 PDNS_RECORD QueryResultWide;
127 PDNS_RECORD ConvertedRecord = 0, LastRecord = 0;
128
129 Buffer = DnsWToC( Name );
130
131 Status = DnsQuery_A( Buffer, Type, Options, Servers, &QueryResultWide,
132 Reserved );
133
134 while( Status == ERROR_SUCCESS && QueryResultWide ) {
135 switch( QueryResultWide->wType ) {
136 case DNS_TYPE_A:
137 case DNS_TYPE_WKS:
138 #ifndef __USE_W32API
139 case DNS_TYPE_AAAA:
140 case DNS_TYPE_KEY:
141 #endif
142 ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0,
143 sizeof(DNS_RECORD) );
144 ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
145 ConvertedRecord->wType = QueryResultWide->wType;
146 ConvertedRecord->wDataLength = QueryResultWide->wDataLength;
147 memcpy( ConvertedRecord, QueryResultWide,
148 QueryResultWide->wDataLength );
149 break;
150
151 case DNS_TYPE_CNAME:
152 case DNS_TYPE_PTR:
153 case DNS_TYPE_NS:
154 case DNS_TYPE_MB:
155 case DNS_TYPE_MD:
156 case DNS_TYPE_MF:
157 case DNS_TYPE_MG:
158 case DNS_TYPE_MR:
159 ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0,
160 sizeof(DNS_RECORD) );
161 ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
162 ConvertedRecord->wType = QueryResultWide->wType;
163 ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATA);
164 ConvertedRecord->Data.PTR.pNameHost =
165 (PCHAR)DnsCToW( QueryResultWide->Data.PTR.pNameHost );
166 break;
167 case DNS_TYPE_MINFO:
168 #ifndef __USE_W32API
169 case DNS_TYPE_RP:
170 #endif
171 ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0,
172 sizeof(DNS_RECORD) );
173 ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
174 ConvertedRecord->wType = QueryResultWide->wType;
175 ConvertedRecord->wDataLength = sizeof(DNS_MINFO_DATA);
176 ConvertedRecord->Data.MINFO.pNameMailbox =
177 (PCHAR)DnsCToW( QueryResultWide->Data.MINFO.pNameMailbox );
178 ConvertedRecord->Data.MINFO.pNameErrorsMailbox =
179 (PCHAR)DnsCToW( QueryResultWide->Data.MINFO.pNameErrorsMailbox );
180 break;
181
182 case DNS_TYPE_MX:
183 #ifndef __USE_W32API
184 case DNS_TYPE_AFSDB:
185 case DNS_TYPE_RT:
186 #endif
187 ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0,
188 sizeof(DNS_RECORD) );
189 ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
190 ConvertedRecord->wType = QueryResultWide->wType;
191 ConvertedRecord->wDataLength = sizeof(DNS_MX_DATA);
192 ConvertedRecord->Data.MX.pNameExchange =
193 (PCHAR)DnsCToW( QueryResultWide->Data.MX.pNameExchange );
194 ConvertedRecord->Data.MX.wPreference =
195 QueryResultWide->Data.MX.wPreference;
196 break;
197
198 #ifndef __USE_W32API
199 case DNS_TYPE_TXT:
200 case DNS_TYPE_ISDN:
201 #endif
202 case DNS_TYPE_HINFO:
203 ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0,
204 sizeof(DNS_TXT_DATA) +
205 QueryResultWide->
206 Data.TXT.dwStringCount );
207 ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
208 ConvertedRecord->wType = QueryResultWide->wType;
209 ConvertedRecord->wDataLength =
210 sizeof(DNS_TXT_DATA) +
211 (sizeof(PWCHAR) * QueryResultWide->Data.TXT.dwStringCount);
212 ConvertedRecord->Data.TXT.dwStringCount =
213 QueryResultWide->Data.TXT.dwStringCount;
214 for( i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++ ) {
215 ConvertedRecord->Data.TXT.pStringArray[i] =
216 (PCHAR)DnsCToW( QueryResultWide->Data.TXT.pStringArray[i] );
217 }
218 break;
219
220 case DNS_TYPE_NULL:
221 ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0,
222 sizeof(DNS_NULL_DATA) +
223 QueryResultWide->
224 Data.Null.dwByteCount );
225 ConvertedRecord->pName = (PCHAR)DnsCToW( QueryResultWide->pName );
226 ConvertedRecord->wType = QueryResultWide->wType;
227 ConvertedRecord->wDataLength =
228 sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount;
229 ConvertedRecord->Data.Null.dwByteCount =
230 QueryResultWide->Data.Null.dwByteCount;
231 memcpy( &ConvertedRecord->Data.Null.Data,
232 &QueryResultWide->Data.Null.Data,
233 QueryResultWide->Data.Null.dwByteCount );
234 break;
235
236 #ifndef __USE_W32API
237 case DNS_TYPE_SIG:
238 ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0,
239 sizeof(DNS_RECORDA) );
240 ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
241 ConvertedRecord->wType = QueryResultWide->wType;
242 ConvertedRecord->wDataLength = sizeof(DNS_SIG_DATAA);
243 memcpy( &ConvertedRecord->Data.SIG,
244 &QueryResultWide->Data.SIG,
245 sizeof(QueryResultWide->Data.SIG) );
246 ConvertedRecord->Data.SIG.pNameSigner =
247 DnsCToW( QueryResultWide->Data.SIG.pNameSigner );
248 break;
249
250 case DNS_TYPE_NXT:
251 ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0,
252 sizeof(DNS_RECORDA) );
253 ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
254 ConvertedRecord->wType = QueryResultWide->wType;
255 ConvertedRecord->wDataLength = sizeof(DNS_NXT_DATAA);
256 memcpy( &ConvertedRecord->Data.NXT,
257 &QueryResultWide->Data.NXT,
258 sizeof(QueryResultWide->Data.NXT) );
259 ConvertedRecord->Data.NXT.pNameNext =
260 DnsCToW( QueryResultWide->Data.NXT.pNameNext );
261 break;
262
263 case DNS_TYPE_SRV:
264 ConvertedRecord = RtlAllocateHeap( RtlGetProcessHeap(), 0,
265 sizeof(DNS_RECORDA) );
266 ConvertedRecord->pName = DnsCToW( QueryResultWide->pName );
267 ConvertedRecord->wType = QueryResultWide->wType;
268 ConvertedRecord->wDataLength = sizeof(DNS_SRV_DATAA);
269 memcpy( &ConvertedRecord->Data.SRV,
270 &QueryResultWide->Data.SRV,
271 sizeof(QueryResultWide->Data.SRV) );
272 ConvertedRecord->Data.SRV.pNameTarget =
273 DnsCToW( QueryResultWide->Data.SRV.pNameTarget );
274 break;
275 #endif
276 }
277
278 if( LastRecord ) {
279 LastRecord->pNext = ConvertedRecord;
280 LastRecord = LastRecord->pNext;
281 } else {
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 DnsQuery_UTF8
295 ( LPCSTR Name,
296 WORD Type,
297 DWORD Options,
298 PIP4_ARRAY Servers,
299 PDNS_RECORD *QueryResultSet,
300 PVOID *Reserved ) {
301 return DnsQuery_UTF8( Name, Type, Options, Servers, QueryResultSet,
302 Reserved );
303 }
304
305 void DnsIntFreeRecordList( PDNS_RECORD ToDelete ) {
306 int i;
307 PDNS_RECORD next = 0;
308
309 while( ToDelete ) {
310 if( ToDelete->pName )
311 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->pName );
312 switch( ToDelete->wType ) {
313 case DNS_TYPE_CNAME:
314 case DNS_TYPE_PTR:
315 case DNS_TYPE_NS:
316 case DNS_TYPE_MB:
317 case DNS_TYPE_MD:
318 case DNS_TYPE_MF:
319 case DNS_TYPE_MG:
320 case DNS_TYPE_MR:
321 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.PTR.pNameHost );
322 break;
323 case DNS_TYPE_MINFO:
324 #ifndef __USE_W32API
325 case DNS_TYPE_RP:
326 RtlFreeHeap( RtlGetProcessHeap(), 0,
327 ToDelete->Data.MINFO.pNameMailbox );
328 RtlFreeHeap( RtlGetProcessHeap(), 0,
329 ToDelete->Data.MINFO.pNameErrorsMailbox );
330 break;
331
332 case DNS_TYPE_AFSDB:
333 case DNS_TYPE_RT:
334 #endif
335 case DNS_TYPE_MX:
336 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.MX.pNameExchange );
337 break;
338
339 #ifndef __USE_W32API
340 case DNS_TYPE_TXT:
341 case DNS_TYPE_ISDN:
342 #endif
343 case DNS_TYPE_HINFO:
344 for( i = 0; i < ToDelete->Data.TXT.dwStringCount; i++ ) {
345 RtlFreeHeap( RtlGetProcessHeap(), 0,
346 ToDelete->Data.TXT.pStringArray[i] );
347 }
348 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray );
349 break;
350
351 #ifndef __USE_W32API
352 case DNS_TYPE_SIG:
353 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.SIG.pNameSigner );
354 break;
355
356 case DNS_TYPE_NXT:
357 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.NXT.pNameNext );
358 break;
359
360 case DNS_TYPE_SRV:
361 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete->Data.SRV.pNameTarget );
362 break;
363 #endif
364 }
365
366 next = ToDelete->pNext;
367 RtlFreeHeap( RtlGetProcessHeap(), 0, ToDelete );
368 ToDelete = next;
369 }
370 }