blob: 2116b113da4199dc576a56bb6022a1fedc2ae69c [file] [log] [blame]
Hans Leidekkerda1d7242006-05-09 10:47:06 +02001/*
2 * DNS support
3 *
4 * Copyright (C) 2006 Hans Leidekker
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Hans Leidekkerda1d7242006-05-09 10:47:06 +020019 */
20
21#include "config.h"
22#include "wine/port.h"
23#include "wine/debug.h"
24
25#include <stdarg.h>
26#include <string.h>
27#include <sys/types.h>
28
29#ifdef HAVE_NETINET_IN_H
30# include <netinet/in.h>
31#endif
32#ifdef HAVE_ARPA_NAMESER_H
33# include <arpa/nameser.h>
34#endif
35#ifdef HAVE_RESOLV_H
36# include <resolv.h>
37#endif
38#ifdef HAVE_NETDB_H
39# include <netdb.h>
40#endif
41
42#include "windef.h"
43#include "winbase.h"
44#include "winerror.h"
45#include "winnls.h"
46#include "windns.h"
Hans Leidekker02ca30e2006-05-31 15:46:58 +020047#include "nb30.h"
Hans Leidekkerda1d7242006-05-09 10:47:06 +020048
49#include "dnsapi.h"
50
51WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
52
53#ifdef HAVE_RESOLV
54
Francois Gouget5a8fc342007-04-30 02:06:11 +020055/* call res_init() just once because of a bug in Mac OS X 10.4 */
Hans Leidekkerc0584902010-03-23 16:12:11 +010056/* call once per thread on systems that have per-thread _res */
Hans Leidekkerdfebf1b2007-04-18 20:39:33 +020057static void initialise_resolver( void )
58{
Hans Leidekkerc0584902010-03-23 16:12:11 +010059 if ((_res.options & RES_INIT) == 0)
Hans Leidekkerdfebf1b2007-04-18 20:39:33 +020060 res_init();
Hans Leidekkerdfebf1b2007-04-18 20:39:33 +020061}
Hans Leidekkerda1d7242006-05-09 10:47:06 +020062
Hans Leidekker59317392006-05-29 12:47:31 +020063static const char *dns_section_to_str( ns_sect section )
64{
65 switch (section)
66 {
67 case ns_s_qd: return "Question";
68 case ns_s_an: return "Answer";
69 case ns_s_ns: return "Authority";
70 case ns_s_ar: return "Additional";
71 default:
72 {
73 static char tmp[5];
74 FIXME( "unknown section: 0x%02x\n", section );
75 sprintf( tmp, "0x%02x", section );
76 return tmp;
77 }
78 }
79}
80
81static unsigned long dns_map_options( DWORD options )
82{
83 unsigned long ret = 0;
84
Hans Leidekker5213b4a2006-06-17 15:13:28 +020085 if (options == DNS_QUERY_STANDARD)
86 return RES_DEFAULT;
87
Hans Leidekker59317392006-05-29 12:47:31 +020088 if (options & DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE)
89 ret |= RES_IGNTC;
90 if (options & DNS_QUERY_USE_TCP_ONLY)
91 ret |= RES_USEVC;
92 if (options & DNS_QUERY_NO_RECURSION)
93 ret &= ~RES_RECURSE;
94 if (options & DNS_QUERY_NO_LOCAL_NAME)
95 ret &= ~RES_DNSRCH;
96 if (options & DNS_QUERY_NO_HOSTS_FILE)
97 ret |= RES_NOALIASES;
98 if (options & DNS_QUERY_TREAT_AS_FQDN)
99 ret &= ~RES_DEFNAMES;
100
101 if (options & DNS_QUERY_DONT_RESET_TTL_VALUES)
102 FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
103 if (options & DNS_QUERY_RESERVED)
104 FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
105 if (options & DNS_QUERY_WIRE_ONLY)
106 FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
107 if (options & DNS_QUERY_NO_WIRE_QUERY)
108 FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
109 if (options & DNS_QUERY_BYPASS_CACHE)
110 FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
111 if (options & DNS_QUERY_RETURN_MESSAGE)
112 FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
113
114 if (options & DNS_QUERY_NO_NETBT)
115 TRACE( "netbios query disabled\n" );
116
117 return ret;
118}
119
120static DNS_STATUS dns_map_error( int error )
121{
122 switch (error)
123 {
Alexandre Julliard826cc602006-05-31 14:17:04 +0200124 case ns_r_noerror: return ERROR_SUCCESS;
125 case ns_r_formerr: return DNS_ERROR_RCODE_FORMAT_ERROR;
126 case ns_r_servfail: return DNS_ERROR_RCODE_SERVER_FAILURE;
127 case ns_r_nxdomain: return DNS_ERROR_RCODE_NAME_ERROR;
128 case ns_r_notimpl: return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
129 case ns_r_refused: return DNS_ERROR_RCODE_REFUSED;
130 case ns_r_yxdomain: return DNS_ERROR_RCODE_YXDOMAIN;
131 case ns_r_yxrrset: return DNS_ERROR_RCODE_YXRRSET;
132 case ns_r_nxrrset: return DNS_ERROR_RCODE_NXRRSET;
133 case ns_r_notauth: return DNS_ERROR_RCODE_NOTAUTH;
134 case ns_r_notzone: return DNS_ERROR_RCODE_NOTZONE;
Hans Leidekker59317392006-05-29 12:47:31 +0200135 default:
136 FIXME( "unmapped error code: %d\n", error );
137 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
138 }
139}
140
141static DNS_STATUS dns_map_h_errno( int error )
142{
143 switch (error)
144 {
145 case NO_DATA:
146 case HOST_NOT_FOUND: return DNS_ERROR_RCODE_NAME_ERROR;
147 case TRY_AGAIN: return DNS_ERROR_RCODE_SERVER_FAILURE;
148 case NO_RECOVERY: return DNS_ERROR_RCODE_REFUSED;
149 case NETDB_INTERNAL: return DNS_ERROR_RCODE;
150 default:
151 FIXME( "unmapped error code: %d\n", error );
152 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
153 }
154}
155
156static char *dns_dname_from_msg( ns_msg msg, const unsigned char *pos )
157{
158 int len;
159 char *str, dname[NS_MAXDNAME] = ".";
160
161 /* returns *compressed* length, ignore it */
Hans Leidekker06cd0e22012-02-03 10:47:42 +0100162 dns_ns_name_uncompress( ns_msg_base(msg), ns_msg_end(msg), pos, dname, sizeof(dname) );
Hans Leidekker59317392006-05-29 12:47:31 +0200163
164 len = strlen( dname );
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100165 str = heap_alloc( len + 1 );
Hans Leidekker59317392006-05-29 12:47:31 +0200166 if (str) strcpy( str, dname );
167 return str;
168}
169
170static char *dns_str_from_rdata( const unsigned char *rdata )
171{
172 char *str;
173 unsigned int len = rdata[0];
174
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100175 str = heap_alloc( len + 1 );
Hans Leidekker59317392006-05-29 12:47:31 +0200176 if (str)
177 {
178 memcpy( str, ++rdata, len );
179 str[len] = '\0';
180 }
181 return str;
182}
183
Andrew Talbot275e1042007-04-25 21:41:05 +0100184static unsigned int dns_get_record_size( const ns_rr *rr )
Hans Leidekker59317392006-05-29 12:47:31 +0200185{
186 const unsigned char *pos = rr->rdata;
187 unsigned int num = 0, size = sizeof(DNS_RECORDA);
188
189 switch (rr->type)
190 {
Alexandre Julliard826cc602006-05-31 14:17:04 +0200191 case ns_t_key:
Hans Leidekker59317392006-05-29 12:47:31 +0200192 {
193 pos += sizeof(WORD) + sizeof(BYTE) + sizeof(BYTE);
194 size += rr->rdata + rr->rdlength - pos - 1;
195 break;
196 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200197 case ns_t_sig:
Hans Leidekker59317392006-05-29 12:47:31 +0200198 {
199 pos += sizeof(PCHAR) + sizeof(WORD) + 2 * sizeof(BYTE);
200 pos += 3 * sizeof(DWORD) + 2 * sizeof(WORD);
201 size += rr->rdata + rr->rdlength - pos - 1;
202 break;
203 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200204 case ns_t_hinfo:
205 case ns_t_isdn:
206 case ns_t_txt:
207 case ns_t_x25:
Hans Leidekker59317392006-05-29 12:47:31 +0200208 {
209 while (pos[0] && pos < rr->rdata + rr->rdlength)
210 {
211 num++;
212 pos += pos[0] + 1;
213 }
214 size += (num - 1) * sizeof(PCHAR);
215 break;
216 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200217 case ns_t_null:
Hans Leidekker59317392006-05-29 12:47:31 +0200218 {
219 size += rr->rdlength - 1;
220 break;
221 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200222 case ns_t_nxt:
223 case ns_t_wks:
Hans Leidekker59317392006-05-29 12:47:31 +0200224 case 0xff01: /* WINS */
225 {
226 FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
227 break;
228 }
229 default:
230 break;
231 }
232 return size;
233}
234
Andrew Talbot275e1042007-04-25 21:41:05 +0100235static DNS_STATUS dns_copy_rdata( ns_msg msg, const ns_rr *rr, DNS_RECORDA *r, WORD *dlen )
Hans Leidekker59317392006-05-29 12:47:31 +0200236{
237 DNS_STATUS ret = ERROR_SUCCESS;
238 const unsigned char *pos = rr->rdata;
239 unsigned int i, size;
240
241 switch (rr->type)
242 {
Alexandre Julliard826cc602006-05-31 14:17:04 +0200243 case ns_t_a:
Hans Leidekker59317392006-05-29 12:47:31 +0200244 {
Andrew Talbotba645ea2006-09-09 17:10:21 +0100245 r->Data.A.IpAddress = *(const DWORD *)pos;
Hans Leidekker59317392006-05-29 12:47:31 +0200246 *dlen = sizeof(DNS_A_DATA);
247 break;
248 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200249 case ns_t_aaaa:
Hans Leidekker59317392006-05-29 12:47:31 +0200250 {
251 for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
252 {
Andrew Talbotba645ea2006-09-09 17:10:21 +0100253 r->Data.AAAA.Ip6Address.IP6Dword[i] = *(const DWORD *)pos;
Hans Leidekker59317392006-05-29 12:47:31 +0200254 pos += sizeof(DWORD);
255 }
256
257 *dlen = sizeof(DNS_AAAA_DATA);
258 break;
259 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200260 case ns_t_key:
Hans Leidekker59317392006-05-29 12:47:31 +0200261 {
262 /* FIXME: byte order? */
Andrew Talbotba645ea2006-09-09 17:10:21 +0100263 r->Data.KEY.wFlags = *(const WORD *)pos; pos += sizeof(WORD);
Andrew Talbot1a1d0a32007-12-10 22:03:24 +0000264 r->Data.KEY.chProtocol = *pos++;
265 r->Data.KEY.chAlgorithm = *pos++;
Hans Leidekker59317392006-05-29 12:47:31 +0200266
267 size = rr->rdata + rr->rdlength - pos;
268
269 for (i = 0; i < size; i++)
Andrew Talbot1a1d0a32007-12-10 22:03:24 +0000270 r->Data.KEY.Key[i] = *pos++;
Hans Leidekker59317392006-05-29 12:47:31 +0200271
272 *dlen = sizeof(DNS_KEY_DATA) + (size - 1) * sizeof(BYTE);
273 break;
274 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200275 case ns_t_rp:
276 case ns_t_minfo:
Hans Leidekker59317392006-05-29 12:47:31 +0200277 {
278 r->Data.MINFO.pNameMailbox = dns_dname_from_msg( msg, pos );
279 if (!r->Data.MINFO.pNameMailbox) return ERROR_NOT_ENOUGH_MEMORY;
280
281 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
282 return DNS_ERROR_BAD_PACKET;
283
284 r->Data.MINFO.pNameErrorsMailbox = dns_dname_from_msg( msg, pos );
285 if (!r->Data.MINFO.pNameErrorsMailbox)
286 {
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100287 heap_free( r->Data.MINFO.pNameMailbox );
Hans Leidekker59317392006-05-29 12:47:31 +0200288 return ERROR_NOT_ENOUGH_MEMORY;
289 }
290
291 *dlen = sizeof(DNS_MINFO_DATAA);
292 break;
293 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200294 case ns_t_afsdb:
295 case ns_t_rt:
296 case ns_t_mx:
Hans Leidekker59317392006-05-29 12:47:31 +0200297 {
Andrew Talbotba645ea2006-09-09 17:10:21 +0100298 r->Data.MX.wPreference = ntohs( *(const WORD *)pos );
Hans Leidekker59317392006-05-29 12:47:31 +0200299 r->Data.MX.pNameExchange = dns_dname_from_msg( msg, pos + sizeof(WORD) );
300 if (!r->Data.MX.pNameExchange) return ERROR_NOT_ENOUGH_MEMORY;
301
302 *dlen = sizeof(DNS_MX_DATAA);
303 break;
304 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200305 case ns_t_null:
Hans Leidekker59317392006-05-29 12:47:31 +0200306 {
307 r->Data.Null.dwByteCount = rr->rdlength;
308 memcpy( r->Data.Null.Data, rr->rdata, rr->rdlength );
309
310 *dlen = sizeof(DNS_NULL_DATA) + rr->rdlength - 1;
311 break;
312 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200313 case ns_t_cname:
314 case ns_t_ns:
315 case ns_t_mb:
316 case ns_t_md:
317 case ns_t_mf:
318 case ns_t_mg:
319 case ns_t_mr:
320 case ns_t_ptr:
Hans Leidekker59317392006-05-29 12:47:31 +0200321 {
322 r->Data.PTR.pNameHost = dns_dname_from_msg( msg, pos );
323 if (!r->Data.PTR.pNameHost) return ERROR_NOT_ENOUGH_MEMORY;
324
325 *dlen = sizeof(DNS_PTR_DATAA);
326 break;
327 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200328 case ns_t_sig:
Hans Leidekker59317392006-05-29 12:47:31 +0200329 {
330 r->Data.SIG.pNameSigner = dns_dname_from_msg( msg, pos );
331 if (!r->Data.SIG.pNameSigner) return ERROR_NOT_ENOUGH_MEMORY;
332
333 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
334 return DNS_ERROR_BAD_PACKET;
335
336 /* FIXME: byte order? */
Andrew Talbotba645ea2006-09-09 17:10:21 +0100337 r->Data.SIG.wTypeCovered = *(const WORD *)pos; pos += sizeof(WORD);
Andrew Talbot1a1d0a32007-12-10 22:03:24 +0000338 r->Data.SIG.chAlgorithm = *pos++;
339 r->Data.SIG.chLabelCount = *pos++;
Andrew Talbotba645ea2006-09-09 17:10:21 +0100340 r->Data.SIG.dwOriginalTtl = *(const DWORD *)pos; pos += sizeof(DWORD);
341 r->Data.SIG.dwExpiration = *(const DWORD *)pos; pos += sizeof(DWORD);
342 r->Data.SIG.dwTimeSigned = *(const DWORD *)pos; pos += sizeof(DWORD);
343 r->Data.SIG.wKeyTag = *(const WORD *)pos;
Hans Leidekker59317392006-05-29 12:47:31 +0200344
345 size = rr->rdata + rr->rdlength - pos;
346
347 for (i = 0; i < size; i++)
Andrew Talbot1a1d0a32007-12-10 22:03:24 +0000348 r->Data.SIG.Signature[i] = *pos++;
Hans Leidekker59317392006-05-29 12:47:31 +0200349
350 *dlen = sizeof(DNS_SIG_DATAA) + (size - 1) * sizeof(BYTE);
351 break;
352 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200353 case ns_t_soa:
Hans Leidekker59317392006-05-29 12:47:31 +0200354 {
355 r->Data.SOA.pNamePrimaryServer = dns_dname_from_msg( msg, pos );
356 if (!r->Data.SOA.pNamePrimaryServer) return ERROR_NOT_ENOUGH_MEMORY;
357
358 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
359 return DNS_ERROR_BAD_PACKET;
360
361 r->Data.SOA.pNameAdministrator = dns_dname_from_msg( msg, pos );
362 if (!r->Data.SOA.pNameAdministrator)
363 {
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100364 heap_free( r->Data.SOA.pNamePrimaryServer );
Hans Leidekker59317392006-05-29 12:47:31 +0200365 return ERROR_NOT_ENOUGH_MEMORY;
366 }
367
368 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
369 return DNS_ERROR_BAD_PACKET;
370
Andrew Talbotba645ea2006-09-09 17:10:21 +0100371 r->Data.SOA.dwSerialNo = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
372 r->Data.SOA.dwRefresh = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
373 r->Data.SOA.dwRetry = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
374 r->Data.SOA.dwExpire = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
375 r->Data.SOA.dwDefaultTtl = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
Hans Leidekker59317392006-05-29 12:47:31 +0200376
377 *dlen = sizeof(DNS_SOA_DATAA);
378 break;
379 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200380 case ns_t_srv:
Hans Leidekker59317392006-05-29 12:47:31 +0200381 {
Andrew Talbotba645ea2006-09-09 17:10:21 +0100382 r->Data.SRV.wPriority = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
383 r->Data.SRV.wWeight = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
384 r->Data.SRV.wPort = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
Hans Leidekker59317392006-05-29 12:47:31 +0200385
386 r->Data.SRV.pNameTarget = dns_dname_from_msg( msg, pos );
387 if (!r->Data.SRV.pNameTarget) return ERROR_NOT_ENOUGH_MEMORY;
388
389 *dlen = sizeof(DNS_SRV_DATAA);
390 break;
391 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200392 case ns_t_hinfo:
393 case ns_t_isdn:
394 case ns_t_x25:
395 case ns_t_txt:
Hans Leidekker59317392006-05-29 12:47:31 +0200396 {
397 i = 0;
398 while (pos[0] && pos < rr->rdata + rr->rdlength)
399 {
400 r->Data.TXT.pStringArray[i] = dns_str_from_rdata( pos );
401 if (!r->Data.TXT.pStringArray[i])
402 {
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100403 while (i > 0) heap_free( r->Data.TXT.pStringArray[--i] );
Hans Leidekker59317392006-05-29 12:47:31 +0200404 return ERROR_NOT_ENOUGH_MEMORY;
405 }
406 i++;
407 pos += pos[0] + 1;
408 }
409 r->Data.TXT.dwStringCount = i;
410 *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR);
411 break;
412 }
Alexandre Julliard826cc602006-05-31 14:17:04 +0200413 case ns_t_atma:
414 case ns_t_loc:
415 case ns_t_nxt:
416 case ns_t_tsig:
417 case ns_t_wks:
Hans Leidekker59317392006-05-29 12:47:31 +0200418 case 0x00f9: /* TKEY */
419 case 0xff01: /* WINS */
420 case 0xff02: /* WINSR */
421 default:
422 FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
423 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
424 }
425
426 return ret;
427}
428
429static DNS_STATUS dns_copy_record( ns_msg msg, ns_sect section,
430 unsigned short num, DNS_RECORDA **recp )
431{
432 DNS_STATUS ret;
433 DNS_RECORDA *record;
434 WORD dlen;
435 ns_rr rr;
436
437 if (dns_ns_parserr( &msg, section, num, &rr ) < 0)
438 return DNS_ERROR_BAD_PACKET;
439
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100440 if (!(record = heap_alloc_zero( dns_get_record_size( &rr ) )))
Hans Leidekker59317392006-05-29 12:47:31 +0200441 return ERROR_NOT_ENOUGH_MEMORY;
442
443 record->pName = dns_strdup_u( rr.name );
444 if (!record->pName)
445 {
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100446 heap_free( record );
Hans Leidekker59317392006-05-29 12:47:31 +0200447 return ERROR_NOT_ENOUGH_MEMORY;
448 }
449
450 record->wType = rr.type;
451 record->Flags.S.Section = section;
452 record->Flags.S.CharSet = DnsCharSetUtf8;
453 record->dwTtl = rr.ttl;
454
455 if ((ret = dns_copy_rdata( msg, &rr, record, &dlen )))
456 {
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100457 heap_free( record->pName );
458 heap_free( record );
Hans Leidekker59317392006-05-29 12:47:31 +0200459 return ret;
460 }
461 record->wDataLength = dlen;
462 *recp = record;
463
464 TRACE( "found %s record in %s section\n",
465 dns_type_to_str( rr.type ), dns_section_to_str( section ) );
466 return ERROR_SUCCESS;
467}
468
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200469#define DEFAULT_TTL 1200
470
471static DNS_STATUS dns_do_query_netbios( PCSTR name, DNS_RECORDA **recp )
472{
473 NCB ncb;
474 UCHAR ret;
475 DNS_RRSET rrset;
476 FIND_NAME_BUFFER *buffer;
477 FIND_NAME_HEADER *header;
478 DNS_RECORDA *record = NULL;
479 unsigned int i, len;
Hans Leidekkera9a04fb2006-09-13 14:36:49 +0200480 DNS_STATUS status = ERROR_INVALID_NAME;
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200481
482 len = strlen( name );
483 if (len >= NCBNAMSZ) return DNS_ERROR_RCODE_NAME_ERROR;
484
485 DNS_RRSET_INIT( rrset );
486
487 memset( &ncb, 0, sizeof(ncb) );
488 ncb.ncb_command = NCBFINDNAME;
489
490 memset( ncb.ncb_callname, ' ', sizeof(ncb.ncb_callname) );
491 memcpy( ncb.ncb_callname, name, len );
Hans Leidekkerdfd22082006-07-10 22:18:50 +0200492 ncb.ncb_callname[NCBNAMSZ - 1] = '\0';
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200493
494 ret = Netbios( &ncb );
495 if (ret != NRC_GOODRET) return ERROR_INVALID_NAME;
496
497 header = (FIND_NAME_HEADER *)ncb.ncb_buffer;
498 buffer = (FIND_NAME_BUFFER *)((char *)header + sizeof(FIND_NAME_HEADER));
499
500 for (i = 0; i < header->node_count; i++)
501 {
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100502 record = heap_alloc_zero( sizeof(DNS_RECORDA) );
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200503 if (!record)
504 {
Hans Leidekkera9a04fb2006-09-13 14:36:49 +0200505 status = ERROR_NOT_ENOUGH_MEMORY;
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200506 goto exit;
507 }
508 else
509 {
510 record->pName = dns_strdup_u( name );
511 if (!record->pName)
512 {
Hans Leidekkera9a04fb2006-09-13 14:36:49 +0200513 status = ERROR_NOT_ENOUGH_MEMORY;
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200514 goto exit;
515 }
516
517 record->wType = DNS_TYPE_A;
518 record->Flags.S.Section = DnsSectionAnswer;
519 record->Flags.S.CharSet = DnsCharSetUtf8;
520 record->dwTtl = DEFAULT_TTL;
521
522 /* FIXME: network byte order? */
523 record->Data.A.IpAddress = *(DWORD *)((char *)buffer[i].destination_addr + 2);
524
525 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
526 }
527 }
Kai Blin2620cea2007-01-01 12:42:44 +0100528 status = ERROR_SUCCESS;
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200529
530exit:
531 DNS_RRSET_TERMINATE( rrset );
532
Hans Leidekkera9a04fb2006-09-13 14:36:49 +0200533 if (status != ERROR_SUCCESS)
Hans Leidekkerf9b213f2006-06-17 15:24:32 +0200534 DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200535 else
536 *recp = (DNS_RECORDA *)rrset.pFirstRR;
537
Hans Leidekkera9a04fb2006-09-13 14:36:49 +0200538 return status;
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200539}
540
Hans Leidekker18cd1432010-09-08 19:26:43 +0200541/* res_init() must have been called before calling these three functions.
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200542 */
Andrew Talbot275e1042007-04-25 21:41:05 +0100543static DNS_STATUS dns_set_serverlist( const IP4_ARRAY *addrs )
Hans Leidekker59317392006-05-29 12:47:31 +0200544{
Andrew Talbot5ca83ae2008-07-31 22:26:26 +0100545 int i;
Hans Leidekker59317392006-05-29 12:47:31 +0200546
547 if (addrs->AddrCount > MAXNS)
548 {
Hans Leidekker4e3b3de2006-09-30 12:07:06 +0200549 WARN( "too many servers: %d only using the first: %d\n",
Hans Leidekker59317392006-05-29 12:47:31 +0200550 addrs->AddrCount, MAXNS );
551 _res.nscount = MAXNS;
552 }
553 else _res.nscount = addrs->AddrCount;
554
555 for (i = 0; i < _res.nscount; i++)
556 _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
557
558 return ERROR_SUCCESS;
559}
560
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200561static DNS_STATUS dns_get_serverlist( PIP4_ARRAY addrs, PDWORD len )
562{
Andrew Talbot5ca83ae2008-07-31 22:26:26 +0100563 unsigned int size;
564 int i;
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200565
Michael Stefaniucc0092bc2012-12-10 10:17:02 +0100566 size = FIELD_OFFSET(IP4_ARRAY, AddrArray[_res.nscount]);
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200567 if (!addrs || *len < size)
568 {
569 *len = size;
570 return ERROR_INSUFFICIENT_BUFFER;
571 }
572
573 addrs->AddrCount = _res.nscount;
574
575 for (i = 0; i < _res.nscount; i++)
576 addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
577
578 return ERROR_SUCCESS;
579}
580
Hans Leidekker59317392006-05-29 12:47:31 +0200581static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options,
582 PDNS_RECORDA *result )
583{
584 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
585
586 unsigned int i, num;
587 unsigned char answer[NS_PACKETSZ];
588 ns_sect sections[] = { ns_s_an, ns_s_ar };
589 ns_msg msg;
590
591 DNS_RECORDA *record = NULL;
592 DNS_RRSET rrset;
593 int len;
594
595 DNS_RRSET_INIT( rrset );
596
Alexandre Julliard826cc602006-05-31 14:17:04 +0200597 len = res_query( name, ns_c_in, type, answer, sizeof(answer) );
Hans Leidekker59317392006-05-29 12:47:31 +0200598 if (len < 0)
599 {
600 ret = dns_map_h_errno( h_errno );
601 goto exit;
602 }
603
604 if (dns_ns_initparse( answer, len, &msg ) < 0)
605 {
606 ret = DNS_ERROR_BAD_PACKET;
607 goto exit;
608 }
609
Alexandre Julliardd1a33832006-05-31 14:25:49 +0200610#define RCODE_MASK 0x0f
611 if ((msg._flags & RCODE_MASK) != ns_r_noerror)
Hans Leidekker59317392006-05-29 12:47:31 +0200612 {
Alexandre Julliardd1a33832006-05-31 14:25:49 +0200613 ret = dns_map_error( msg._flags & RCODE_MASK );
Hans Leidekker59317392006-05-29 12:47:31 +0200614 goto exit;
615 }
616
617 for (i = 0; i < sizeof(sections)/sizeof(sections[0]); i++)
618 {
619 for (num = 0; num < ns_msg_count( msg, sections[i] ); num++)
620 {
621 ret = dns_copy_record( msg, sections[i], num, &record );
622 if (ret != ERROR_SUCCESS) goto exit;
623
624 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
625 }
626 }
627
628exit:
629 DNS_RRSET_TERMINATE( rrset );
630
631 if (ret != ERROR_SUCCESS)
632 DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
633 else
634 *result = (DNS_RECORDA *)rrset.pFirstRR;
635
636 return ret;
637}
638
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200639#endif /* HAVE_RESOLV */
640
Hans Leidekker59317392006-05-29 12:47:31 +0200641/******************************************************************************
642 * DnsQuery_A [DNSAPI.@]
643 *
644 */
Francois Gougetcace3f92007-08-04 03:20:32 +0200645DNS_STATUS WINAPI DnsQuery_A( PCSTR name, WORD type, DWORD options, PVOID servers,
Hans Leidekker59317392006-05-29 12:47:31 +0200646 PDNS_RECORDA *result, PVOID *reserved )
647{
648 WCHAR *nameW;
649 DNS_RECORDW *resultW;
650 DNS_STATUS status;
651
Hans Leidekker4e3b3de2006-09-30 12:07:06 +0200652 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
Hans Leidekker59317392006-05-29 12:47:31 +0200653 options, servers, result, reserved );
654
655 if (!name || !result)
656 return ERROR_INVALID_PARAMETER;
657
658 nameW = dns_strdup_aw( name );
659 if (!nameW) return ERROR_NOT_ENOUGH_MEMORY;
660
661 status = DnsQuery_W( nameW, type, options, servers, &resultW, reserved );
662
663 if (status == ERROR_SUCCESS)
664 {
665 *result = (DNS_RECORDA *)DnsRecordSetCopyEx(
666 (DNS_RECORD *)resultW, DnsCharSetUnicode, DnsCharSetAnsi );
667
668 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
669 DnsRecordListFree( (DNS_RECORD *)resultW, DnsFreeRecordList );
670 }
671
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100672 heap_free( nameW );
Hans Leidekker59317392006-05-29 12:47:31 +0200673 return status;
674}
675
676/******************************************************************************
677 * DnsQuery_UTF8 [DNSAPI.@]
678 *
679 */
Francois Gougetcace3f92007-08-04 03:20:32 +0200680DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID servers,
Hans Leidekker59317392006-05-29 12:47:31 +0200681 PDNS_RECORDA *result, PVOID *reserved )
682{
683 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
684#ifdef HAVE_RESOLV
685
Hans Leidekker4e3b3de2006-09-30 12:07:06 +0200686 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
Hans Leidekker59317392006-05-29 12:47:31 +0200687 options, servers, result, reserved );
688
689 if (!name || !result)
690 return ERROR_INVALID_PARAMETER;
691
Hans Leidekkerdfebf1b2007-04-18 20:39:33 +0200692 initialise_resolver();
Hans Leidekker59317392006-05-29 12:47:31 +0200693 _res.options |= dns_map_options( options );
694
695 if (servers && (ret = dns_set_serverlist( servers )))
696 return ret;
697
698 ret = dns_do_query( name, type, options, result );
699
Hans Leidekker02ca30e2006-05-31 15:46:58 +0200700 if (ret == DNS_ERROR_RCODE_NAME_ERROR && type == DNS_TYPE_A &&
701 !(options & DNS_QUERY_NO_NETBT))
702 {
703 TRACE( "dns lookup failed, trying netbios query\n" );
704 ret = dns_do_query_netbios( name, result );
705 }
706
Hans Leidekker59317392006-05-29 12:47:31 +0200707#endif
708 return ret;
709}
710
711/******************************************************************************
712 * DnsQuery_W [DNSAPI.@]
713 *
714 */
Francois Gougetcace3f92007-08-04 03:20:32 +0200715DNS_STATUS WINAPI DnsQuery_W( PCWSTR name, WORD type, DWORD options, PVOID servers,
Hans Leidekker59317392006-05-29 12:47:31 +0200716 PDNS_RECORDW *result, PVOID *reserved )
717{
718 char *nameU;
719 DNS_RECORDA *resultA;
720 DNS_STATUS status;
721
Hans Leidekker4e3b3de2006-09-30 12:07:06 +0200722 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_w(name), dns_type_to_str( type ),
Hans Leidekker59317392006-05-29 12:47:31 +0200723 options, servers, result, reserved );
724
725 if (!name || !result)
726 return ERROR_INVALID_PARAMETER;
727
728 nameU = dns_strdup_wu( name );
729 if (!nameU) return ERROR_NOT_ENOUGH_MEMORY;
730
731 status = DnsQuery_UTF8( nameU, type, options, servers, &resultA, reserved );
732
733 if (status == ERROR_SUCCESS)
734 {
735 *result = (DNS_RECORDW *)DnsRecordSetCopyEx(
736 (DNS_RECORD *)resultA, DnsCharSetUtf8, DnsCharSetUnicode );
737
738 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
739 DnsRecordListFree( (DNS_RECORD *)resultA, DnsFreeRecordList );
740 }
741
Michael Stefaniucb3ff6802007-11-28 00:11:14 +0100742 heap_free( nameU );
Hans Leidekker59317392006-05-29 12:47:31 +0200743 return status;
744}
745
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200746static DNS_STATUS dns_get_hostname_a( COMPUTER_NAME_FORMAT format,
Francois Gougetca3a2412007-08-08 10:47:03 +0200747 PSTR buffer, PDWORD len )
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200748{
749 char name[256];
Marcus Meissner8a4748b2008-09-14 10:13:17 +0200750 DWORD size = sizeof(name)/sizeof(name[0]);
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200751
752 if (!GetComputerNameExA( format, name, &size ))
753 return DNS_ERROR_NAME_DOES_NOT_EXIST;
754
755 if (!buffer || (size = lstrlenA( name ) + 1) > *len)
756 {
757 *len = size;
758 return ERROR_INSUFFICIENT_BUFFER;
759 }
760
761 lstrcpyA( buffer, name );
762 return ERROR_SUCCESS;
763}
764
765static DNS_STATUS dns_get_hostname_w( COMPUTER_NAME_FORMAT format,
Francois Gougetca3a2412007-08-08 10:47:03 +0200766 PWSTR buffer, PDWORD len )
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200767{
768 WCHAR name[256];
Marcus Meissner8a4748b2008-09-14 10:13:17 +0200769 DWORD size = sizeof(name)/sizeof(name[0]);
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200770
771 if (!GetComputerNameExW( format, name, &size ))
772 return DNS_ERROR_NAME_DOES_NOT_EXIST;
773
774 if (!buffer || (size = lstrlenW( name ) + 1) > *len)
775 {
776 *len = size;
777 return ERROR_INSUFFICIENT_BUFFER;
778 }
779
780 lstrcpyW( buffer, name );
781 return ERROR_SUCCESS;
782}
783
784/******************************************************************************
785 * DnsQueryConfig [DNSAPI.@]
786 *
787 */
Francois Gouget4040ece2007-09-18 00:39:58 +0200788DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR adapter,
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200789 PVOID reserved, PVOID buffer, PDWORD len )
790{
791 DNS_STATUS ret = ERROR_INVALID_PARAMETER;
792
Hans Leidekker4e3b3de2006-09-30 12:07:06 +0200793 TRACE( "(%d,0x%08x,%s,%p,%p,%p)\n", config, flag, debugstr_w(adapter),
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200794 reserved, buffer, len );
795
796 if (!len) return ERROR_INVALID_PARAMETER;
797
798 switch (config)
799 {
800 case DnsConfigDnsServerList:
801 {
802#ifdef HAVE_RESOLV
Hans Leidekkerdfebf1b2007-04-18 20:39:33 +0200803 initialise_resolver();
Hans Leidekkera9a04fb2006-09-13 14:36:49 +0200804 ret = dns_get_serverlist( buffer, len );
Hans Leidekkerda1d7242006-05-09 10:47:06 +0200805 break;
806#else
807 WARN( "compiled without resolver support\n" );
808 break;
809#endif
810 }
811 case DnsConfigHostName_A:
812 case DnsConfigHostName_UTF8:
813 return dns_get_hostname_a( ComputerNameDnsHostname, buffer, len );
814
815 case DnsConfigFullHostName_A:
816 case DnsConfigFullHostName_UTF8:
817 return dns_get_hostname_a( ComputerNameDnsFullyQualified, buffer, len );
818
819 case DnsConfigPrimaryDomainName_A:
820 case DnsConfigPrimaryDomainName_UTF8:
821 return dns_get_hostname_a( ComputerNameDnsDomain, buffer, len );
822
823 case DnsConfigHostName_W:
824 return dns_get_hostname_w( ComputerNameDnsHostname, buffer, len );
825
826 case DnsConfigFullHostName_W:
827 return dns_get_hostname_w( ComputerNameDnsFullyQualified, buffer, len );
828
829 case DnsConfigPrimaryDomainName_W:
830 return dns_get_hostname_w( ComputerNameDnsDomain, buffer, len );
831
832 case DnsConfigAdapterDomainName_A:
833 case DnsConfigAdapterDomainName_W:
834 case DnsConfigAdapterDomainName_UTF8:
835 case DnsConfigSearchList:
836 case DnsConfigAdapterInfo:
837 case DnsConfigPrimaryHostNameRegistrationEnabled:
838 case DnsConfigAdapterHostNameRegistrationEnabled:
839 case DnsConfigAddressRegistrationMaxCount:
840 FIXME( "unimplemented config type %d\n", config );
841 break;
842
843 default:
844 WARN( "unknown config type: %d\n", config );
845 break;
846 }
847 return ret;
848}