push 0f15bbd80d260bbd8adf052e820484a405c49375
[wine/hacks.git] / dlls / dnsapi / query.c
blob60e74563d96ead22f845b7e7431fbc5abcb2f183
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 static int resolver_initialised;
70 /* call res_init() just once because of a bug in Mac OS X 10.4 */
71 static void initialise_resolver( void )
73 if (!resolver_initialised)
75 res_init();
76 resolver_initialised = 1;
80 static const char *dns_section_to_str( ns_sect section )
82 switch (section)
84 case ns_s_qd: return "Question";
85 case ns_s_an: return "Answer";
86 case ns_s_ns: return "Authority";
87 case ns_s_ar: return "Additional";
88 default:
90 static char tmp[5];
91 FIXME( "unknown section: 0x%02x\n", section );
92 sprintf( tmp, "0x%02x", section );
93 return tmp;
98 static unsigned long dns_map_options( DWORD options )
100 unsigned long ret = 0;
102 if (options == DNS_QUERY_STANDARD)
103 return RES_DEFAULT;
105 if (options & DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE)
106 ret |= RES_IGNTC;
107 if (options & DNS_QUERY_USE_TCP_ONLY)
108 ret |= RES_USEVC;
109 if (options & DNS_QUERY_NO_RECURSION)
110 ret &= ~RES_RECURSE;
111 if (options & DNS_QUERY_NO_LOCAL_NAME)
112 ret &= ~RES_DNSRCH;
113 if (options & DNS_QUERY_NO_HOSTS_FILE)
114 ret |= RES_NOALIASES;
115 if (options & DNS_QUERY_TREAT_AS_FQDN)
116 ret &= ~RES_DEFNAMES;
118 if (options & DNS_QUERY_DONT_RESET_TTL_VALUES)
119 FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
120 if (options & DNS_QUERY_RESERVED)
121 FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
122 if (options & DNS_QUERY_WIRE_ONLY)
123 FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
124 if (options & DNS_QUERY_NO_WIRE_QUERY)
125 FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
126 if (options & DNS_QUERY_BYPASS_CACHE)
127 FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
128 if (options & DNS_QUERY_RETURN_MESSAGE)
129 FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
131 if (options & DNS_QUERY_NO_NETBT)
132 TRACE( "netbios query disabled\n" );
134 return ret;
137 static DNS_STATUS dns_map_error( int error )
139 switch (error)
141 case ns_r_noerror: return ERROR_SUCCESS;
142 case ns_r_formerr: return DNS_ERROR_RCODE_FORMAT_ERROR;
143 case ns_r_servfail: return DNS_ERROR_RCODE_SERVER_FAILURE;
144 case ns_r_nxdomain: return DNS_ERROR_RCODE_NAME_ERROR;
145 case ns_r_notimpl: return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
146 case ns_r_refused: return DNS_ERROR_RCODE_REFUSED;
147 case ns_r_yxdomain: return DNS_ERROR_RCODE_YXDOMAIN;
148 case ns_r_yxrrset: return DNS_ERROR_RCODE_YXRRSET;
149 case ns_r_nxrrset: return DNS_ERROR_RCODE_NXRRSET;
150 case ns_r_notauth: return DNS_ERROR_RCODE_NOTAUTH;
151 case ns_r_notzone: return DNS_ERROR_RCODE_NOTZONE;
152 default:
153 FIXME( "unmapped error code: %d\n", error );
154 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
158 static DNS_STATUS dns_map_h_errno( int error )
160 switch (error)
162 case NO_DATA:
163 case HOST_NOT_FOUND: return DNS_ERROR_RCODE_NAME_ERROR;
164 case TRY_AGAIN: return DNS_ERROR_RCODE_SERVER_FAILURE;
165 case NO_RECOVERY: return DNS_ERROR_RCODE_REFUSED;
166 case NETDB_INTERNAL: return DNS_ERROR_RCODE;
167 default:
168 FIXME( "unmapped error code: %d\n", error );
169 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
173 static char *dns_dname_from_msg( ns_msg msg, const unsigned char *pos )
175 int len;
176 char *str, dname[NS_MAXDNAME] = ".";
178 /* returns *compressed* length, ignore it */
179 len = dns_ns_name_uncompress( ns_msg_base( msg ), ns_msg_end( msg ),
180 pos, dname, sizeof(dname) );
182 len = strlen( dname );
183 str = heap_alloc( len + 1 );
184 if (str) strcpy( str, dname );
185 return str;
188 static char *dns_str_from_rdata( const unsigned char *rdata )
190 char *str;
191 unsigned int len = rdata[0];
193 str = heap_alloc( len + 1 );
194 if (str)
196 memcpy( str, ++rdata, len );
197 str[len] = '\0';
199 return str;
202 static unsigned int dns_get_record_size( const ns_rr *rr )
204 const unsigned char *pos = rr->rdata;
205 unsigned int num = 0, size = sizeof(DNS_RECORDA);
207 switch (rr->type)
209 case ns_t_key:
211 pos += sizeof(WORD) + sizeof(BYTE) + sizeof(BYTE);
212 size += rr->rdata + rr->rdlength - pos - 1;
213 break;
215 case ns_t_sig:
217 pos += sizeof(PCHAR) + sizeof(WORD) + 2 * sizeof(BYTE);
218 pos += 3 * sizeof(DWORD) + 2 * sizeof(WORD);
219 size += rr->rdata + rr->rdlength - pos - 1;
220 break;
222 case ns_t_hinfo:
223 case ns_t_isdn:
224 case ns_t_txt:
225 case ns_t_x25:
227 while (pos[0] && pos < rr->rdata + rr->rdlength)
229 num++;
230 pos += pos[0] + 1;
232 size += (num - 1) * sizeof(PCHAR);
233 break;
235 case ns_t_null:
237 size += rr->rdlength - 1;
238 break;
240 case ns_t_nxt:
241 case ns_t_wks:
242 case 0xff01: /* WINS */
244 FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
245 break;
247 default:
248 break;
250 return size;
253 static DNS_STATUS dns_copy_rdata( ns_msg msg, const ns_rr *rr, DNS_RECORDA *r, WORD *dlen )
255 DNS_STATUS ret = ERROR_SUCCESS;
256 const unsigned char *pos = rr->rdata;
257 unsigned int i, size;
259 switch (rr->type)
261 case ns_t_a:
263 r->Data.A.IpAddress = *(const DWORD *)pos;
264 *dlen = sizeof(DNS_A_DATA);
265 break;
267 case ns_t_aaaa:
269 for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
271 r->Data.AAAA.Ip6Address.IP6Dword[i] = *(const DWORD *)pos;
272 pos += sizeof(DWORD);
275 *dlen = sizeof(DNS_AAAA_DATA);
276 break;
278 case ns_t_key:
280 /* FIXME: byte order? */
281 r->Data.KEY.wFlags = *(const WORD *)pos; pos += sizeof(WORD);
282 r->Data.KEY.chProtocol = *(const BYTE *)pos++;
283 r->Data.KEY.chAlgorithm = *(const BYTE *)pos++;
285 size = rr->rdata + rr->rdlength - pos;
287 for (i = 0; i < size; i++)
288 r->Data.KEY.Key[i] = *(const BYTE *)pos++;
290 *dlen = sizeof(DNS_KEY_DATA) + (size - 1) * sizeof(BYTE);
291 break;
293 case ns_t_rp:
294 case ns_t_minfo:
296 r->Data.MINFO.pNameMailbox = dns_dname_from_msg( msg, pos );
297 if (!r->Data.MINFO.pNameMailbox) return ERROR_NOT_ENOUGH_MEMORY;
299 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
300 return DNS_ERROR_BAD_PACKET;
302 r->Data.MINFO.pNameErrorsMailbox = dns_dname_from_msg( msg, pos );
303 if (!r->Data.MINFO.pNameErrorsMailbox)
305 heap_free( r->Data.MINFO.pNameMailbox );
306 return ERROR_NOT_ENOUGH_MEMORY;
309 *dlen = sizeof(DNS_MINFO_DATAA);
310 break;
312 case ns_t_afsdb:
313 case ns_t_rt:
314 case ns_t_mx:
316 r->Data.MX.wPreference = ntohs( *(const WORD *)pos );
317 r->Data.MX.pNameExchange = dns_dname_from_msg( msg, pos + sizeof(WORD) );
318 if (!r->Data.MX.pNameExchange) return ERROR_NOT_ENOUGH_MEMORY;
320 *dlen = sizeof(DNS_MX_DATAA);
321 break;
323 case ns_t_null:
325 r->Data.Null.dwByteCount = rr->rdlength;
326 memcpy( r->Data.Null.Data, rr->rdata, rr->rdlength );
328 *dlen = sizeof(DNS_NULL_DATA) + rr->rdlength - 1;
329 break;
331 case ns_t_cname:
332 case ns_t_ns:
333 case ns_t_mb:
334 case ns_t_md:
335 case ns_t_mf:
336 case ns_t_mg:
337 case ns_t_mr:
338 case ns_t_ptr:
340 r->Data.PTR.pNameHost = dns_dname_from_msg( msg, pos );
341 if (!r->Data.PTR.pNameHost) return ERROR_NOT_ENOUGH_MEMORY;
343 *dlen = sizeof(DNS_PTR_DATAA);
344 break;
346 case ns_t_sig:
348 r->Data.SIG.pNameSigner = dns_dname_from_msg( msg, pos );
349 if (!r->Data.SIG.pNameSigner) return ERROR_NOT_ENOUGH_MEMORY;
351 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
352 return DNS_ERROR_BAD_PACKET;
354 /* FIXME: byte order? */
355 r->Data.SIG.wTypeCovered = *(const WORD *)pos; pos += sizeof(WORD);
356 r->Data.SIG.chAlgorithm = *(const BYTE *)pos++;
357 r->Data.SIG.chLabelCount = *(const BYTE *)pos++;
358 r->Data.SIG.dwOriginalTtl = *(const DWORD *)pos; pos += sizeof(DWORD);
359 r->Data.SIG.dwExpiration = *(const DWORD *)pos; pos += sizeof(DWORD);
360 r->Data.SIG.dwTimeSigned = *(const DWORD *)pos; pos += sizeof(DWORD);
361 r->Data.SIG.wKeyTag = *(const WORD *)pos;
363 size = rr->rdata + rr->rdlength - pos;
365 for (i = 0; i < size; i++)
366 r->Data.SIG.Signature[i] = *(const BYTE *)pos++;
368 *dlen = sizeof(DNS_SIG_DATAA) + (size - 1) * sizeof(BYTE);
369 break;
371 case ns_t_soa:
373 r->Data.SOA.pNamePrimaryServer = dns_dname_from_msg( msg, pos );
374 if (!r->Data.SOA.pNamePrimaryServer) return ERROR_NOT_ENOUGH_MEMORY;
376 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
377 return DNS_ERROR_BAD_PACKET;
379 r->Data.SOA.pNameAdministrator = dns_dname_from_msg( msg, pos );
380 if (!r->Data.SOA.pNameAdministrator)
382 heap_free( r->Data.SOA.pNamePrimaryServer );
383 return ERROR_NOT_ENOUGH_MEMORY;
386 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
387 return DNS_ERROR_BAD_PACKET;
389 r->Data.SOA.dwSerialNo = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
390 r->Data.SOA.dwRefresh = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
391 r->Data.SOA.dwRetry = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
392 r->Data.SOA.dwExpire = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
393 r->Data.SOA.dwDefaultTtl = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
395 *dlen = sizeof(DNS_SOA_DATAA);
396 break;
398 case ns_t_srv:
400 r->Data.SRV.wPriority = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
401 r->Data.SRV.wWeight = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
402 r->Data.SRV.wPort = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
404 r->Data.SRV.pNameTarget = dns_dname_from_msg( msg, pos );
405 if (!r->Data.SRV.pNameTarget) return ERROR_NOT_ENOUGH_MEMORY;
407 *dlen = sizeof(DNS_SRV_DATAA);
408 break;
410 case ns_t_hinfo:
411 case ns_t_isdn:
412 case ns_t_x25:
413 case ns_t_txt:
415 i = 0;
416 while (pos[0] && pos < rr->rdata + rr->rdlength)
418 r->Data.TXT.pStringArray[i] = dns_str_from_rdata( pos );
419 if (!r->Data.TXT.pStringArray[i])
421 while (i > 0) heap_free( r->Data.TXT.pStringArray[--i] );
422 return ERROR_NOT_ENOUGH_MEMORY;
424 i++;
425 pos += pos[0] + 1;
427 r->Data.TXT.dwStringCount = i;
428 *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR);
429 break;
431 case ns_t_atma:
432 case ns_t_loc:
433 case ns_t_nxt:
434 case ns_t_tsig:
435 case ns_t_wks:
436 case 0x00f9: /* TKEY */
437 case 0xff01: /* WINS */
438 case 0xff02: /* WINSR */
439 default:
440 FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
441 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
444 return ret;
447 static DNS_STATUS dns_copy_record( ns_msg msg, ns_sect section,
448 unsigned short num, DNS_RECORDA **recp )
450 DNS_STATUS ret;
451 DNS_RECORDA *record;
452 WORD dlen;
453 ns_rr rr;
455 if (dns_ns_parserr( &msg, section, num, &rr ) < 0)
456 return DNS_ERROR_BAD_PACKET;
458 if (!(record = heap_alloc_zero( dns_get_record_size( &rr ) )))
459 return ERROR_NOT_ENOUGH_MEMORY;
461 record->pName = dns_strdup_u( rr.name );
462 if (!record->pName)
464 heap_free( record );
465 return ERROR_NOT_ENOUGH_MEMORY;
468 record->wType = rr.type;
469 record->Flags.S.Section = section;
470 record->Flags.S.CharSet = DnsCharSetUtf8;
471 record->dwTtl = rr.ttl;
473 if ((ret = dns_copy_rdata( msg, &rr, record, &dlen )))
475 heap_free( record->pName );
476 heap_free( record );
477 return ret;
479 record->wDataLength = dlen;
480 *recp = record;
482 TRACE( "found %s record in %s section\n",
483 dns_type_to_str( rr.type ), dns_section_to_str( section ) );
484 return ERROR_SUCCESS;
487 #define DEFAULT_TTL 1200
489 static DNS_STATUS dns_do_query_netbios( PCSTR name, DNS_RECORDA **recp )
491 NCB ncb;
492 UCHAR ret;
493 DNS_RRSET rrset;
494 FIND_NAME_BUFFER *buffer;
495 FIND_NAME_HEADER *header;
496 DNS_RECORDA *record = NULL;
497 unsigned int i, len;
498 DNS_STATUS status = ERROR_INVALID_NAME;
500 len = strlen( name );
501 if (len >= NCBNAMSZ) return DNS_ERROR_RCODE_NAME_ERROR;
503 DNS_RRSET_INIT( rrset );
505 memset( &ncb, 0, sizeof(ncb) );
506 ncb.ncb_command = NCBFINDNAME;
508 memset( ncb.ncb_callname, ' ', sizeof(ncb.ncb_callname) );
509 memcpy( ncb.ncb_callname, name, len );
510 ncb.ncb_callname[NCBNAMSZ - 1] = '\0';
512 ret = Netbios( &ncb );
513 if (ret != NRC_GOODRET) return ERROR_INVALID_NAME;
515 header = (FIND_NAME_HEADER *)ncb.ncb_buffer;
516 buffer = (FIND_NAME_BUFFER *)((char *)header + sizeof(FIND_NAME_HEADER));
518 for (i = 0; i < header->node_count; i++)
520 record = heap_alloc_zero( sizeof(DNS_RECORDA) );
521 if (!record)
523 status = ERROR_NOT_ENOUGH_MEMORY;
524 goto exit;
526 else
528 record->pName = dns_strdup_u( name );
529 if (!record->pName)
531 status = ERROR_NOT_ENOUGH_MEMORY;
532 goto exit;
535 record->wType = DNS_TYPE_A;
536 record->Flags.S.Section = DnsSectionAnswer;
537 record->Flags.S.CharSet = DnsCharSetUtf8;
538 record->dwTtl = DEFAULT_TTL;
540 /* FIXME: network byte order? */
541 record->Data.A.IpAddress = *(DWORD *)((char *)buffer[i].destination_addr + 2);
543 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
546 status = ERROR_SUCCESS;
548 exit:
549 DNS_RRSET_TERMINATE( rrset );
551 if (status != ERROR_SUCCESS)
552 DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
553 else
554 *recp = (DNS_RECORDA *)rrset.pFirstRR;
556 return status;
559 /* The resolver lock must be held and res_init() must have been
560 * called before calling these three functions.
562 static DNS_STATUS dns_set_serverlist( const IP4_ARRAY *addrs )
564 unsigned int i;
566 if (addrs->AddrCount > MAXNS)
568 WARN( "too many servers: %d only using the first: %d\n",
569 addrs->AddrCount, MAXNS );
570 _res.nscount = MAXNS;
572 else _res.nscount = addrs->AddrCount;
574 for (i = 0; i < _res.nscount; i++)
575 _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
577 return ERROR_SUCCESS;
580 static DNS_STATUS dns_get_serverlist( PIP4_ARRAY addrs, PDWORD len )
582 unsigned int i, size;
584 size = sizeof(IP4_ARRAY) + sizeof(IP4_ADDRESS) * (_res.nscount - 1);
585 if (!addrs || *len < size)
587 *len = size;
588 return ERROR_INSUFFICIENT_BUFFER;
591 addrs->AddrCount = _res.nscount;
593 for (i = 0; i < _res.nscount; i++)
594 addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
596 return ERROR_SUCCESS;
599 static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options,
600 PDNS_RECORDA *result )
602 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
604 unsigned int i, num;
605 unsigned char answer[NS_PACKETSZ];
606 ns_sect sections[] = { ns_s_an, ns_s_ar };
607 ns_msg msg;
609 DNS_RECORDA *record = NULL;
610 DNS_RRSET rrset;
611 int len;
613 DNS_RRSET_INIT( rrset );
615 len = res_query( name, ns_c_in, type, answer, sizeof(answer) );
616 if (len < 0)
618 ret = dns_map_h_errno( h_errno );
619 goto exit;
622 if (dns_ns_initparse( answer, len, &msg ) < 0)
624 ret = DNS_ERROR_BAD_PACKET;
625 goto exit;
628 #define RCODE_MASK 0x0f
629 if ((msg._flags & RCODE_MASK) != ns_r_noerror)
631 ret = dns_map_error( msg._flags & RCODE_MASK );
632 goto exit;
635 for (i = 0; i < sizeof(sections)/sizeof(sections[0]); i++)
637 for (num = 0; num < ns_msg_count( msg, sections[i] ); num++)
639 ret = dns_copy_record( msg, sections[i], num, &record );
640 if (ret != ERROR_SUCCESS) goto exit;
642 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
646 exit:
647 DNS_RRSET_TERMINATE( rrset );
649 if (ret != ERROR_SUCCESS)
650 DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
651 else
652 *result = (DNS_RECORDA *)rrset.pFirstRR;
654 return ret;
657 #endif /* HAVE_RESOLV */
659 /******************************************************************************
660 * DnsQuery_A [DNSAPI.@]
663 DNS_STATUS WINAPI DnsQuery_A( PCSTR name, WORD type, DWORD options, PVOID servers,
664 PDNS_RECORDA *result, PVOID *reserved )
666 WCHAR *nameW;
667 DNS_RECORDW *resultW;
668 DNS_STATUS status;
670 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
671 options, servers, result, reserved );
673 if (!name || !result)
674 return ERROR_INVALID_PARAMETER;
676 nameW = dns_strdup_aw( name );
677 if (!nameW) return ERROR_NOT_ENOUGH_MEMORY;
679 status = DnsQuery_W( nameW, type, options, servers, &resultW, reserved );
681 if (status == ERROR_SUCCESS)
683 *result = (DNS_RECORDA *)DnsRecordSetCopyEx(
684 (DNS_RECORD *)resultW, DnsCharSetUnicode, DnsCharSetAnsi );
686 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
687 DnsRecordListFree( (DNS_RECORD *)resultW, DnsFreeRecordList );
690 heap_free( nameW );
691 return status;
694 /******************************************************************************
695 * DnsQuery_UTF8 [DNSAPI.@]
698 DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID servers,
699 PDNS_RECORDA *result, PVOID *reserved )
701 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
702 #ifdef HAVE_RESOLV
704 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
705 options, servers, result, reserved );
707 if (!name || !result)
708 return ERROR_INVALID_PARAMETER;
710 LOCK_RESOLVER();
712 initialise_resolver();
713 _res.options |= dns_map_options( options );
715 if (servers && (ret = dns_set_serverlist( servers )))
717 UNLOCK_RESOLVER();
718 return ret;
721 ret = dns_do_query( name, type, options, result );
723 if (ret == DNS_ERROR_RCODE_NAME_ERROR && type == DNS_TYPE_A &&
724 !(options & DNS_QUERY_NO_NETBT))
726 TRACE( "dns lookup failed, trying netbios query\n" );
727 ret = dns_do_query_netbios( name, result );
730 UNLOCK_RESOLVER();
732 #endif
733 return ret;
736 /******************************************************************************
737 * DnsQuery_W [DNSAPI.@]
740 DNS_STATUS WINAPI DnsQuery_W( PCWSTR name, WORD type, DWORD options, PVOID servers,
741 PDNS_RECORDW *result, PVOID *reserved )
743 char *nameU;
744 DNS_RECORDA *resultA;
745 DNS_STATUS status;
747 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_w(name), dns_type_to_str( type ),
748 options, servers, result, reserved );
750 if (!name || !result)
751 return ERROR_INVALID_PARAMETER;
753 nameU = dns_strdup_wu( name );
754 if (!nameU) return ERROR_NOT_ENOUGH_MEMORY;
756 status = DnsQuery_UTF8( nameU, type, options, servers, &resultA, reserved );
758 if (status == ERROR_SUCCESS)
760 *result = (DNS_RECORDW *)DnsRecordSetCopyEx(
761 (DNS_RECORD *)resultA, DnsCharSetUtf8, DnsCharSetUnicode );
763 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
764 DnsRecordListFree( (DNS_RECORD *)resultA, DnsFreeRecordList );
767 heap_free( nameU );
768 return status;
771 static DNS_STATUS dns_get_hostname_a( COMPUTER_NAME_FORMAT format,
772 PSTR buffer, PDWORD len )
774 char name[256];
775 DWORD size = sizeof(name);
777 if (!GetComputerNameExA( format, name, &size ))
778 return DNS_ERROR_NAME_DOES_NOT_EXIST;
780 if (!buffer || (size = lstrlenA( name ) + 1) > *len)
782 *len = size;
783 return ERROR_INSUFFICIENT_BUFFER;
786 lstrcpyA( buffer, name );
787 return ERROR_SUCCESS;
790 static DNS_STATUS dns_get_hostname_w( COMPUTER_NAME_FORMAT format,
791 PWSTR buffer, PDWORD len )
793 WCHAR name[256];
794 DWORD size = sizeof(name);
796 if (!GetComputerNameExW( format, name, &size ))
797 return DNS_ERROR_NAME_DOES_NOT_EXIST;
799 if (!buffer || (size = lstrlenW( name ) + 1) > *len)
801 *len = size;
802 return ERROR_INSUFFICIENT_BUFFER;
805 lstrcpyW( buffer, name );
806 return ERROR_SUCCESS;
809 /******************************************************************************
810 * DnsQueryConfig [DNSAPI.@]
813 DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR adapter,
814 PVOID reserved, PVOID buffer, PDWORD len )
816 DNS_STATUS ret = ERROR_INVALID_PARAMETER;
818 TRACE( "(%d,0x%08x,%s,%p,%p,%p)\n", config, flag, debugstr_w(adapter),
819 reserved, buffer, len );
821 if (!len) return ERROR_INVALID_PARAMETER;
823 switch (config)
825 case DnsConfigDnsServerList:
827 #ifdef HAVE_RESOLV
828 LOCK_RESOLVER();
830 initialise_resolver();
831 ret = dns_get_serverlist( buffer, len );
833 UNLOCK_RESOLVER();
834 break;
835 #else
836 WARN( "compiled without resolver support\n" );
837 break;
838 #endif
840 case DnsConfigHostName_A:
841 case DnsConfigHostName_UTF8:
842 return dns_get_hostname_a( ComputerNameDnsHostname, buffer, len );
844 case DnsConfigFullHostName_A:
845 case DnsConfigFullHostName_UTF8:
846 return dns_get_hostname_a( ComputerNameDnsFullyQualified, buffer, len );
848 case DnsConfigPrimaryDomainName_A:
849 case DnsConfigPrimaryDomainName_UTF8:
850 return dns_get_hostname_a( ComputerNameDnsDomain, buffer, len );
852 case DnsConfigHostName_W:
853 return dns_get_hostname_w( ComputerNameDnsHostname, buffer, len );
855 case DnsConfigFullHostName_W:
856 return dns_get_hostname_w( ComputerNameDnsFullyQualified, buffer, len );
858 case DnsConfigPrimaryDomainName_W:
859 return dns_get_hostname_w( ComputerNameDnsDomain, buffer, len );
861 case DnsConfigAdapterDomainName_A:
862 case DnsConfigAdapterDomainName_W:
863 case DnsConfigAdapterDomainName_UTF8:
864 case DnsConfigSearchList:
865 case DnsConfigAdapterInfo:
866 case DnsConfigPrimaryHostNameRegistrationEnabled:
867 case DnsConfigAdapterHostNameRegistrationEnabled:
868 case DnsConfigAddressRegistrationMaxCount:
869 FIXME( "unimplemented config type %d\n", config );
870 break;
872 default:
873 WARN( "unknown config type: %d\n", config );
874 break;
876 return ret;