README: Update for 1.2.
[wine/hacks.git] / dlls / dnsapi / query.c
blob60144654ba2b2fca06c1faefeee5a2b89cfc00c1
1 /*
2 * DNS support
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.
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.
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
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
23 #include "wine/debug.h"
25 #include <stdarg.h>
26 #include <string.h>
27 #include <sys/types.h>
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
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winerror.h"
45 #include "winnls.h"
46 #include "windns.h"
47 #include "nb30.h"
49 #include "dnsapi.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
53 #ifdef HAVE_RESOLV
55 static CRITICAL_SECTION resolver_cs;
56 static CRITICAL_SECTION_DEBUG resolver_cs_debug =
58 0, 0, &resolver_cs,
59 { &resolver_cs_debug.ProcessLocksList,
60 &resolver_cs_debug.ProcessLocksList },
61 0, 0, { (DWORD_PTR)(__FILE__ ": resolver_cs") }
63 static CRITICAL_SECTION resolver_cs = { &resolver_cs_debug, -1, 0, 0, 0, 0 };
65 #define LOCK_RESOLVER() do { EnterCriticalSection( &resolver_cs ); } while (0)
66 #define UNLOCK_RESOLVER() do { LeaveCriticalSection( &resolver_cs ); } while (0)
68 /* call res_init() just once because of a bug in Mac OS X 10.4 */
69 /* call once per thread on systems that have per-thread _res */
70 static void initialise_resolver( void )
72 if ((_res.options & RES_INIT) == 0)
73 res_init();
76 static const char *dns_section_to_str( ns_sect section )
78 switch (section)
80 case ns_s_qd: return "Question";
81 case ns_s_an: return "Answer";
82 case ns_s_ns: return "Authority";
83 case ns_s_ar: return "Additional";
84 default:
86 static char tmp[5];
87 FIXME( "unknown section: 0x%02x\n", section );
88 sprintf( tmp, "0x%02x", section );
89 return tmp;
94 static unsigned long dns_map_options( DWORD options )
96 unsigned long ret = 0;
98 if (options == DNS_QUERY_STANDARD)
99 return RES_DEFAULT;
101 if (options & DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE)
102 ret |= RES_IGNTC;
103 if (options & DNS_QUERY_USE_TCP_ONLY)
104 ret |= RES_USEVC;
105 if (options & DNS_QUERY_NO_RECURSION)
106 ret &= ~RES_RECURSE;
107 if (options & DNS_QUERY_NO_LOCAL_NAME)
108 ret &= ~RES_DNSRCH;
109 if (options & DNS_QUERY_NO_HOSTS_FILE)
110 ret |= RES_NOALIASES;
111 if (options & DNS_QUERY_TREAT_AS_FQDN)
112 ret &= ~RES_DEFNAMES;
114 if (options & DNS_QUERY_DONT_RESET_TTL_VALUES)
115 FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
116 if (options & DNS_QUERY_RESERVED)
117 FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
118 if (options & DNS_QUERY_WIRE_ONLY)
119 FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
120 if (options & DNS_QUERY_NO_WIRE_QUERY)
121 FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
122 if (options & DNS_QUERY_BYPASS_CACHE)
123 FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
124 if (options & DNS_QUERY_RETURN_MESSAGE)
125 FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
127 if (options & DNS_QUERY_NO_NETBT)
128 TRACE( "netbios query disabled\n" );
130 return ret;
133 static DNS_STATUS dns_map_error( int error )
135 switch (error)
137 case ns_r_noerror: return ERROR_SUCCESS;
138 case ns_r_formerr: return DNS_ERROR_RCODE_FORMAT_ERROR;
139 case ns_r_servfail: return DNS_ERROR_RCODE_SERVER_FAILURE;
140 case ns_r_nxdomain: return DNS_ERROR_RCODE_NAME_ERROR;
141 case ns_r_notimpl: return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
142 case ns_r_refused: return DNS_ERROR_RCODE_REFUSED;
143 case ns_r_yxdomain: return DNS_ERROR_RCODE_YXDOMAIN;
144 case ns_r_yxrrset: return DNS_ERROR_RCODE_YXRRSET;
145 case ns_r_nxrrset: return DNS_ERROR_RCODE_NXRRSET;
146 case ns_r_notauth: return DNS_ERROR_RCODE_NOTAUTH;
147 case ns_r_notzone: return DNS_ERROR_RCODE_NOTZONE;
148 default:
149 FIXME( "unmapped error code: %d\n", error );
150 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
154 static DNS_STATUS dns_map_h_errno( int error )
156 switch (error)
158 case NO_DATA:
159 case HOST_NOT_FOUND: return DNS_ERROR_RCODE_NAME_ERROR;
160 case TRY_AGAIN: return DNS_ERROR_RCODE_SERVER_FAILURE;
161 case NO_RECOVERY: return DNS_ERROR_RCODE_REFUSED;
162 case NETDB_INTERNAL: return DNS_ERROR_RCODE;
163 default:
164 FIXME( "unmapped error code: %d\n", error );
165 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
169 static char *dns_dname_from_msg( ns_msg msg, const unsigned char *pos )
171 int len;
172 char *str, dname[NS_MAXDNAME] = ".";
174 /* returns *compressed* length, ignore it */
175 len = dns_ns_name_uncompress( ns_msg_base( msg ), ns_msg_end( msg ),
176 pos, dname, sizeof(dname) );
178 len = strlen( dname );
179 str = heap_alloc( len + 1 );
180 if (str) strcpy( str, dname );
181 return str;
184 static char *dns_str_from_rdata( const unsigned char *rdata )
186 char *str;
187 unsigned int len = rdata[0];
189 str = heap_alloc( len + 1 );
190 if (str)
192 memcpy( str, ++rdata, len );
193 str[len] = '\0';
195 return str;
198 static unsigned int dns_get_record_size( const ns_rr *rr )
200 const unsigned char *pos = rr->rdata;
201 unsigned int num = 0, size = sizeof(DNS_RECORDA);
203 switch (rr->type)
205 case ns_t_key:
207 pos += sizeof(WORD) + sizeof(BYTE) + sizeof(BYTE);
208 size += rr->rdata + rr->rdlength - pos - 1;
209 break;
211 case ns_t_sig:
213 pos += sizeof(PCHAR) + sizeof(WORD) + 2 * sizeof(BYTE);
214 pos += 3 * sizeof(DWORD) + 2 * sizeof(WORD);
215 size += rr->rdata + rr->rdlength - pos - 1;
216 break;
218 case ns_t_hinfo:
219 case ns_t_isdn:
220 case ns_t_txt:
221 case ns_t_x25:
223 while (pos[0] && pos < rr->rdata + rr->rdlength)
225 num++;
226 pos += pos[0] + 1;
228 size += (num - 1) * sizeof(PCHAR);
229 break;
231 case ns_t_null:
233 size += rr->rdlength - 1;
234 break;
236 case ns_t_nxt:
237 case ns_t_wks:
238 case 0xff01: /* WINS */
240 FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
241 break;
243 default:
244 break;
246 return size;
249 static DNS_STATUS dns_copy_rdata( ns_msg msg, const ns_rr *rr, DNS_RECORDA *r, WORD *dlen )
251 DNS_STATUS ret = ERROR_SUCCESS;
252 const unsigned char *pos = rr->rdata;
253 unsigned int i, size;
255 switch (rr->type)
257 case ns_t_a:
259 r->Data.A.IpAddress = *(const DWORD *)pos;
260 *dlen = sizeof(DNS_A_DATA);
261 break;
263 case ns_t_aaaa:
265 for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
267 r->Data.AAAA.Ip6Address.IP6Dword[i] = *(const DWORD *)pos;
268 pos += sizeof(DWORD);
271 *dlen = sizeof(DNS_AAAA_DATA);
272 break;
274 case ns_t_key:
276 /* FIXME: byte order? */
277 r->Data.KEY.wFlags = *(const WORD *)pos; pos += sizeof(WORD);
278 r->Data.KEY.chProtocol = *pos++;
279 r->Data.KEY.chAlgorithm = *pos++;
281 size = rr->rdata + rr->rdlength - pos;
283 for (i = 0; i < size; i++)
284 r->Data.KEY.Key[i] = *pos++;
286 *dlen = sizeof(DNS_KEY_DATA) + (size - 1) * sizeof(BYTE);
287 break;
289 case ns_t_rp:
290 case ns_t_minfo:
292 r->Data.MINFO.pNameMailbox = dns_dname_from_msg( msg, pos );
293 if (!r->Data.MINFO.pNameMailbox) return ERROR_NOT_ENOUGH_MEMORY;
295 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
296 return DNS_ERROR_BAD_PACKET;
298 r->Data.MINFO.pNameErrorsMailbox = dns_dname_from_msg( msg, pos );
299 if (!r->Data.MINFO.pNameErrorsMailbox)
301 heap_free( r->Data.MINFO.pNameMailbox );
302 return ERROR_NOT_ENOUGH_MEMORY;
305 *dlen = sizeof(DNS_MINFO_DATAA);
306 break;
308 case ns_t_afsdb:
309 case ns_t_rt:
310 case ns_t_mx:
312 r->Data.MX.wPreference = ntohs( *(const WORD *)pos );
313 r->Data.MX.pNameExchange = dns_dname_from_msg( msg, pos + sizeof(WORD) );
314 if (!r->Data.MX.pNameExchange) return ERROR_NOT_ENOUGH_MEMORY;
316 *dlen = sizeof(DNS_MX_DATAA);
317 break;
319 case ns_t_null:
321 r->Data.Null.dwByteCount = rr->rdlength;
322 memcpy( r->Data.Null.Data, rr->rdata, rr->rdlength );
324 *dlen = sizeof(DNS_NULL_DATA) + rr->rdlength - 1;
325 break;
327 case ns_t_cname:
328 case ns_t_ns:
329 case ns_t_mb:
330 case ns_t_md:
331 case ns_t_mf:
332 case ns_t_mg:
333 case ns_t_mr:
334 case ns_t_ptr:
336 r->Data.PTR.pNameHost = dns_dname_from_msg( msg, pos );
337 if (!r->Data.PTR.pNameHost) return ERROR_NOT_ENOUGH_MEMORY;
339 *dlen = sizeof(DNS_PTR_DATAA);
340 break;
342 case ns_t_sig:
344 r->Data.SIG.pNameSigner = dns_dname_from_msg( msg, pos );
345 if (!r->Data.SIG.pNameSigner) return ERROR_NOT_ENOUGH_MEMORY;
347 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
348 return DNS_ERROR_BAD_PACKET;
350 /* FIXME: byte order? */
351 r->Data.SIG.wTypeCovered = *(const WORD *)pos; pos += sizeof(WORD);
352 r->Data.SIG.chAlgorithm = *pos++;
353 r->Data.SIG.chLabelCount = *pos++;
354 r->Data.SIG.dwOriginalTtl = *(const DWORD *)pos; pos += sizeof(DWORD);
355 r->Data.SIG.dwExpiration = *(const DWORD *)pos; pos += sizeof(DWORD);
356 r->Data.SIG.dwTimeSigned = *(const DWORD *)pos; pos += sizeof(DWORD);
357 r->Data.SIG.wKeyTag = *(const WORD *)pos;
359 size = rr->rdata + rr->rdlength - pos;
361 for (i = 0; i < size; i++)
362 r->Data.SIG.Signature[i] = *pos++;
364 *dlen = sizeof(DNS_SIG_DATAA) + (size - 1) * sizeof(BYTE);
365 break;
367 case ns_t_soa:
369 r->Data.SOA.pNamePrimaryServer = dns_dname_from_msg( msg, pos );
370 if (!r->Data.SOA.pNamePrimaryServer) return ERROR_NOT_ENOUGH_MEMORY;
372 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
373 return DNS_ERROR_BAD_PACKET;
375 r->Data.SOA.pNameAdministrator = dns_dname_from_msg( msg, pos );
376 if (!r->Data.SOA.pNameAdministrator)
378 heap_free( r->Data.SOA.pNamePrimaryServer );
379 return ERROR_NOT_ENOUGH_MEMORY;
382 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
383 return DNS_ERROR_BAD_PACKET;
385 r->Data.SOA.dwSerialNo = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
386 r->Data.SOA.dwRefresh = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
387 r->Data.SOA.dwRetry = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
388 r->Data.SOA.dwExpire = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
389 r->Data.SOA.dwDefaultTtl = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
391 *dlen = sizeof(DNS_SOA_DATAA);
392 break;
394 case ns_t_srv:
396 r->Data.SRV.wPriority = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
397 r->Data.SRV.wWeight = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
398 r->Data.SRV.wPort = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
400 r->Data.SRV.pNameTarget = dns_dname_from_msg( msg, pos );
401 if (!r->Data.SRV.pNameTarget) return ERROR_NOT_ENOUGH_MEMORY;
403 *dlen = sizeof(DNS_SRV_DATAA);
404 break;
406 case ns_t_hinfo:
407 case ns_t_isdn:
408 case ns_t_x25:
409 case ns_t_txt:
411 i = 0;
412 while (pos[0] && pos < rr->rdata + rr->rdlength)
414 r->Data.TXT.pStringArray[i] = dns_str_from_rdata( pos );
415 if (!r->Data.TXT.pStringArray[i])
417 while (i > 0) heap_free( r->Data.TXT.pStringArray[--i] );
418 return ERROR_NOT_ENOUGH_MEMORY;
420 i++;
421 pos += pos[0] + 1;
423 r->Data.TXT.dwStringCount = i;
424 *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR);
425 break;
427 case ns_t_atma:
428 case ns_t_loc:
429 case ns_t_nxt:
430 case ns_t_tsig:
431 case ns_t_wks:
432 case 0x00f9: /* TKEY */
433 case 0xff01: /* WINS */
434 case 0xff02: /* WINSR */
435 default:
436 FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
437 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
440 return ret;
443 static DNS_STATUS dns_copy_record( ns_msg msg, ns_sect section,
444 unsigned short num, DNS_RECORDA **recp )
446 DNS_STATUS ret;
447 DNS_RECORDA *record;
448 WORD dlen;
449 ns_rr rr;
451 if (dns_ns_parserr( &msg, section, num, &rr ) < 0)
452 return DNS_ERROR_BAD_PACKET;
454 if (!(record = heap_alloc_zero( dns_get_record_size( &rr ) )))
455 return ERROR_NOT_ENOUGH_MEMORY;
457 record->pName = dns_strdup_u( rr.name );
458 if (!record->pName)
460 heap_free( record );
461 return ERROR_NOT_ENOUGH_MEMORY;
464 record->wType = rr.type;
465 record->Flags.S.Section = section;
466 record->Flags.S.CharSet = DnsCharSetUtf8;
467 record->dwTtl = rr.ttl;
469 if ((ret = dns_copy_rdata( msg, &rr, record, &dlen )))
471 heap_free( record->pName );
472 heap_free( record );
473 return ret;
475 record->wDataLength = dlen;
476 *recp = record;
478 TRACE( "found %s record in %s section\n",
479 dns_type_to_str( rr.type ), dns_section_to_str( section ) );
480 return ERROR_SUCCESS;
483 #define DEFAULT_TTL 1200
485 static DNS_STATUS dns_do_query_netbios( PCSTR name, DNS_RECORDA **recp )
487 NCB ncb;
488 UCHAR ret;
489 DNS_RRSET rrset;
490 FIND_NAME_BUFFER *buffer;
491 FIND_NAME_HEADER *header;
492 DNS_RECORDA *record = NULL;
493 unsigned int i, len;
494 DNS_STATUS status = ERROR_INVALID_NAME;
496 len = strlen( name );
497 if (len >= NCBNAMSZ) return DNS_ERROR_RCODE_NAME_ERROR;
499 DNS_RRSET_INIT( rrset );
501 memset( &ncb, 0, sizeof(ncb) );
502 ncb.ncb_command = NCBFINDNAME;
504 memset( ncb.ncb_callname, ' ', sizeof(ncb.ncb_callname) );
505 memcpy( ncb.ncb_callname, name, len );
506 ncb.ncb_callname[NCBNAMSZ - 1] = '\0';
508 ret = Netbios( &ncb );
509 if (ret != NRC_GOODRET) return ERROR_INVALID_NAME;
511 header = (FIND_NAME_HEADER *)ncb.ncb_buffer;
512 buffer = (FIND_NAME_BUFFER *)((char *)header + sizeof(FIND_NAME_HEADER));
514 for (i = 0; i < header->node_count; i++)
516 record = heap_alloc_zero( sizeof(DNS_RECORDA) );
517 if (!record)
519 status = ERROR_NOT_ENOUGH_MEMORY;
520 goto exit;
522 else
524 record->pName = dns_strdup_u( name );
525 if (!record->pName)
527 status = ERROR_NOT_ENOUGH_MEMORY;
528 goto exit;
531 record->wType = DNS_TYPE_A;
532 record->Flags.S.Section = DnsSectionAnswer;
533 record->Flags.S.CharSet = DnsCharSetUtf8;
534 record->dwTtl = DEFAULT_TTL;
536 /* FIXME: network byte order? */
537 record->Data.A.IpAddress = *(DWORD *)((char *)buffer[i].destination_addr + 2);
539 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
542 status = ERROR_SUCCESS;
544 exit:
545 DNS_RRSET_TERMINATE( rrset );
547 if (status != ERROR_SUCCESS)
548 DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
549 else
550 *recp = (DNS_RECORDA *)rrset.pFirstRR;
552 return status;
555 /* The resolver lock must be held and res_init() must have been
556 * called before calling these three functions.
558 static DNS_STATUS dns_set_serverlist( const IP4_ARRAY *addrs )
560 int i;
562 if (addrs->AddrCount > MAXNS)
564 WARN( "too many servers: %d only using the first: %d\n",
565 addrs->AddrCount, MAXNS );
566 _res.nscount = MAXNS;
568 else _res.nscount = addrs->AddrCount;
570 for (i = 0; i < _res.nscount; i++)
571 _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
573 return ERROR_SUCCESS;
576 static DNS_STATUS dns_get_serverlist( PIP4_ARRAY addrs, PDWORD len )
578 unsigned int size;
579 int i;
581 size = sizeof(IP4_ARRAY) + sizeof(IP4_ADDRESS) * (_res.nscount - 1);
582 if (!addrs || *len < size)
584 *len = size;
585 return ERROR_INSUFFICIENT_BUFFER;
588 addrs->AddrCount = _res.nscount;
590 for (i = 0; i < _res.nscount; i++)
591 addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
593 return ERROR_SUCCESS;
596 static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options,
597 PDNS_RECORDA *result )
599 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
601 unsigned int i, num;
602 unsigned char answer[NS_PACKETSZ];
603 ns_sect sections[] = { ns_s_an, ns_s_ar };
604 ns_msg msg;
606 DNS_RECORDA *record = NULL;
607 DNS_RRSET rrset;
608 int len;
610 DNS_RRSET_INIT( rrset );
612 len = res_query( name, ns_c_in, type, answer, sizeof(answer) );
613 if (len < 0)
615 ret = dns_map_h_errno( h_errno );
616 goto exit;
619 if (dns_ns_initparse( answer, len, &msg ) < 0)
621 ret = DNS_ERROR_BAD_PACKET;
622 goto exit;
625 #define RCODE_MASK 0x0f
626 if ((msg._flags & RCODE_MASK) != ns_r_noerror)
628 ret = dns_map_error( msg._flags & RCODE_MASK );
629 goto exit;
632 for (i = 0; i < sizeof(sections)/sizeof(sections[0]); i++)
634 for (num = 0; num < ns_msg_count( msg, sections[i] ); num++)
636 ret = dns_copy_record( msg, sections[i], num, &record );
637 if (ret != ERROR_SUCCESS) goto exit;
639 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
643 exit:
644 DNS_RRSET_TERMINATE( rrset );
646 if (ret != ERROR_SUCCESS)
647 DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
648 else
649 *result = (DNS_RECORDA *)rrset.pFirstRR;
651 return ret;
654 #endif /* HAVE_RESOLV */
656 /******************************************************************************
657 * DnsQuery_A [DNSAPI.@]
660 DNS_STATUS WINAPI DnsQuery_A( PCSTR name, WORD type, DWORD options, PVOID servers,
661 PDNS_RECORDA *result, PVOID *reserved )
663 WCHAR *nameW;
664 DNS_RECORDW *resultW;
665 DNS_STATUS status;
667 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
668 options, servers, result, reserved );
670 if (!name || !result)
671 return ERROR_INVALID_PARAMETER;
673 nameW = dns_strdup_aw( name );
674 if (!nameW) return ERROR_NOT_ENOUGH_MEMORY;
676 status = DnsQuery_W( nameW, type, options, servers, &resultW, reserved );
678 if (status == ERROR_SUCCESS)
680 *result = (DNS_RECORDA *)DnsRecordSetCopyEx(
681 (DNS_RECORD *)resultW, DnsCharSetUnicode, DnsCharSetAnsi );
683 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
684 DnsRecordListFree( (DNS_RECORD *)resultW, DnsFreeRecordList );
687 heap_free( nameW );
688 return status;
691 /******************************************************************************
692 * DnsQuery_UTF8 [DNSAPI.@]
695 DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID servers,
696 PDNS_RECORDA *result, PVOID *reserved )
698 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
699 #ifdef HAVE_RESOLV
701 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
702 options, servers, result, reserved );
704 if (!name || !result)
705 return ERROR_INVALID_PARAMETER;
707 LOCK_RESOLVER();
709 initialise_resolver();
710 _res.options |= dns_map_options( options );
712 if (servers && (ret = dns_set_serverlist( servers )))
714 UNLOCK_RESOLVER();
715 return ret;
718 ret = dns_do_query( name, type, options, result );
720 if (ret == DNS_ERROR_RCODE_NAME_ERROR && type == DNS_TYPE_A &&
721 !(options & DNS_QUERY_NO_NETBT))
723 TRACE( "dns lookup failed, trying netbios query\n" );
724 ret = dns_do_query_netbios( name, result );
727 UNLOCK_RESOLVER();
729 #endif
730 return ret;
733 /******************************************************************************
734 * DnsQuery_W [DNSAPI.@]
737 DNS_STATUS WINAPI DnsQuery_W( PCWSTR name, WORD type, DWORD options, PVOID servers,
738 PDNS_RECORDW *result, PVOID *reserved )
740 char *nameU;
741 DNS_RECORDA *resultA;
742 DNS_STATUS status;
744 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_w(name), dns_type_to_str( type ),
745 options, servers, result, reserved );
747 if (!name || !result)
748 return ERROR_INVALID_PARAMETER;
750 nameU = dns_strdup_wu( name );
751 if (!nameU) return ERROR_NOT_ENOUGH_MEMORY;
753 status = DnsQuery_UTF8( nameU, type, options, servers, &resultA, reserved );
755 if (status == ERROR_SUCCESS)
757 *result = (DNS_RECORDW *)DnsRecordSetCopyEx(
758 (DNS_RECORD *)resultA, DnsCharSetUtf8, DnsCharSetUnicode );
760 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
761 DnsRecordListFree( (DNS_RECORD *)resultA, DnsFreeRecordList );
764 heap_free( nameU );
765 return status;
768 static DNS_STATUS dns_get_hostname_a( COMPUTER_NAME_FORMAT format,
769 PSTR buffer, PDWORD len )
771 char name[256];
772 DWORD size = sizeof(name)/sizeof(name[0]);
774 if (!GetComputerNameExA( format, name, &size ))
775 return DNS_ERROR_NAME_DOES_NOT_EXIST;
777 if (!buffer || (size = lstrlenA( name ) + 1) > *len)
779 *len = size;
780 return ERROR_INSUFFICIENT_BUFFER;
783 lstrcpyA( buffer, name );
784 return ERROR_SUCCESS;
787 static DNS_STATUS dns_get_hostname_w( COMPUTER_NAME_FORMAT format,
788 PWSTR buffer, PDWORD len )
790 WCHAR name[256];
791 DWORD size = sizeof(name)/sizeof(name[0]);
793 if (!GetComputerNameExW( format, name, &size ))
794 return DNS_ERROR_NAME_DOES_NOT_EXIST;
796 if (!buffer || (size = lstrlenW( name ) + 1) > *len)
798 *len = size;
799 return ERROR_INSUFFICIENT_BUFFER;
802 lstrcpyW( buffer, name );
803 return ERROR_SUCCESS;
806 /******************************************************************************
807 * DnsQueryConfig [DNSAPI.@]
810 DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR adapter,
811 PVOID reserved, PVOID buffer, PDWORD len )
813 DNS_STATUS ret = ERROR_INVALID_PARAMETER;
815 TRACE( "(%d,0x%08x,%s,%p,%p,%p)\n", config, flag, debugstr_w(adapter),
816 reserved, buffer, len );
818 if (!len) return ERROR_INVALID_PARAMETER;
820 switch (config)
822 case DnsConfigDnsServerList:
824 #ifdef HAVE_RESOLV
825 LOCK_RESOLVER();
827 initialise_resolver();
828 ret = dns_get_serverlist( buffer, len );
830 UNLOCK_RESOLVER();
831 break;
832 #else
833 WARN( "compiled without resolver support\n" );
834 break;
835 #endif
837 case DnsConfigHostName_A:
838 case DnsConfigHostName_UTF8:
839 return dns_get_hostname_a( ComputerNameDnsHostname, buffer, len );
841 case DnsConfigFullHostName_A:
842 case DnsConfigFullHostName_UTF8:
843 return dns_get_hostname_a( ComputerNameDnsFullyQualified, buffer, len );
845 case DnsConfigPrimaryDomainName_A:
846 case DnsConfigPrimaryDomainName_UTF8:
847 return dns_get_hostname_a( ComputerNameDnsDomain, buffer, len );
849 case DnsConfigHostName_W:
850 return dns_get_hostname_w( ComputerNameDnsHostname, buffer, len );
852 case DnsConfigFullHostName_W:
853 return dns_get_hostname_w( ComputerNameDnsFullyQualified, buffer, len );
855 case DnsConfigPrimaryDomainName_W:
856 return dns_get_hostname_w( ComputerNameDnsDomain, buffer, len );
858 case DnsConfigAdapterDomainName_A:
859 case DnsConfigAdapterDomainName_W:
860 case DnsConfigAdapterDomainName_UTF8:
861 case DnsConfigSearchList:
862 case DnsConfigAdapterInfo:
863 case DnsConfigPrimaryHostNameRegistrationEnabled:
864 case DnsConfigAdapterHostNameRegistrationEnabled:
865 case DnsConfigAddressRegistrationMaxCount:
866 FIXME( "unimplemented config type %d\n", config );
867 break;
869 default:
870 WARN( "unknown config type: %d\n", config );
871 break;
873 return ret;