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