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