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