4 * Copyright (C) 2006 Hans Leidekker
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
22 #include "wine/port.h"
23 #include "wine/debug.h"
27 #include <sys/types.h>
29 #ifdef HAVE_NETINET_IN_H
30 # include <netinet/in.h>
32 #ifdef HAVE_ARPA_NAMESER_H
33 # include <arpa/nameser.h>
50 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
54 static CRITICAL_SECTION resolver_cs;
55 static CRITICAL_SECTION_DEBUG resolver_cs_debug =
58 { &resolver_cs_debug.ProcessLocksList,
59 &resolver_cs_debug.ProcessLocksList },
60 0, 0, { (DWORD_PTR)(__FILE__ ": resolver_cs") }
62 static CRITICAL_SECTION resolver_cs = { &resolver_cs_debug, -1, 0, 0, 0, 0 };
64 #define LOCK_RESOLVER() do { EnterCriticalSection( &resolver_cs ); } while (0)
65 #define UNLOCK_RESOLVER() do { LeaveCriticalSection( &resolver_cs ); } while (0)
68 static const char *dns_section_to_str( ns_sect section )
72 case ns_s_qd: return "Question";
73 case ns_s_an: return "Answer";
74 case ns_s_ns: return "Authority";
75 case ns_s_ar: return "Additional";
79 FIXME( "unknown section: 0x%02x\n", section );
80 sprintf( tmp, "0x%02x", section );
86 static unsigned long dns_map_options( DWORD options )
88 unsigned long ret = 0;
90 if (options & DNS_QUERY_STANDARD)
92 if (options & DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE)
94 if (options & DNS_QUERY_USE_TCP_ONLY)
96 if (options & DNS_QUERY_NO_RECURSION)
98 if (options & DNS_QUERY_NO_LOCAL_NAME)
100 if (options & DNS_QUERY_NO_HOSTS_FILE)
101 ret |= RES_NOALIASES;
102 if (options & DNS_QUERY_TREAT_AS_FQDN)
103 ret &= ~RES_DEFNAMES;
105 if (options & DNS_QUERY_DONT_RESET_TTL_VALUES)
106 FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
107 if (options & DNS_QUERY_RESERVED)
108 FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
109 if (options & DNS_QUERY_WIRE_ONLY)
110 FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
111 if (options & DNS_QUERY_NO_WIRE_QUERY)
112 FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
113 if (options & DNS_QUERY_BYPASS_CACHE)
114 FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
115 if (options & DNS_QUERY_RETURN_MESSAGE)
116 FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
118 if (options & DNS_QUERY_NO_NETBT)
119 TRACE( "netbios query disabled\n" );
124 static DNS_STATUS dns_map_error( int error )
128 case NOERROR: return ERROR_SUCCESS;
129 case FORMERR: return DNS_ERROR_RCODE_FORMAT_ERROR;
130 case SERVFAIL: return DNS_ERROR_RCODE_SERVER_FAILURE;
131 case NXDOMAIN: return DNS_ERROR_RCODE_NAME_ERROR;
132 case NOTIMP: return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
133 case REFUSED: return DNS_ERROR_RCODE_REFUSED;
134 case YXDOMAIN: return DNS_ERROR_RCODE_YXDOMAIN;
135 case YXRRSET: return DNS_ERROR_RCODE_YXRRSET;
136 case NXRRSET: return DNS_ERROR_RCODE_NXRRSET;
137 case NOTAUTH: return DNS_ERROR_RCODE_NOTAUTH;
138 case NOTZONE: return DNS_ERROR_RCODE_NOTZONE;
140 FIXME( "unmapped error code: %d\n", error );
141 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
145 static DNS_STATUS dns_map_h_errno( int error )
150 case HOST_NOT_FOUND: return DNS_ERROR_RCODE_NAME_ERROR;
151 case TRY_AGAIN: return DNS_ERROR_RCODE_SERVER_FAILURE;
152 case NO_RECOVERY: return DNS_ERROR_RCODE_REFUSED;
153 case NETDB_INTERNAL: return DNS_ERROR_RCODE;
155 FIXME( "unmapped error code: %d\n", error );
156 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
160 static char *dns_dname_from_msg( ns_msg msg, const unsigned char *pos )
163 char *str, dname[NS_MAXDNAME] = ".";
165 /* returns *compressed* length, ignore it */
166 len = dns_ns_name_uncompress( ns_msg_base( msg ), ns_msg_end( msg ),
167 pos, dname, sizeof(dname) );
169 len = strlen( dname );
170 str = dns_alloc( len + 1 );
171 if (str) strcpy( str, dname );
175 static char *dns_str_from_rdata( const unsigned char *rdata )
178 unsigned int len = rdata[0];
180 str = dns_alloc( len + 1 );
183 memcpy( str, ++rdata, len );
189 static unsigned int dns_get_record_size( ns_rr *rr )
191 const unsigned char *pos = rr->rdata;
192 unsigned int num = 0, size = sizeof(DNS_RECORDA);
198 pos += sizeof(WORD) + sizeof(BYTE) + sizeof(BYTE);
199 size += rr->rdata + rr->rdlength - pos - 1;
204 pos += sizeof(PCHAR) + sizeof(WORD) + 2 * sizeof(BYTE);
205 pos += 3 * sizeof(DWORD) + 2 * sizeof(WORD);
206 size += rr->rdata + rr->rdlength - pos - 1;
214 while (pos[0] && pos < rr->rdata + rr->rdlength)
219 size += (num - 1) * sizeof(PCHAR);
224 size += rr->rdlength - 1;
229 case 0xff01: /* WINS */
231 FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
240 static DNS_STATUS dns_copy_rdata( ns_msg msg, ns_rr *rr, DNS_RECORDA *r, WORD *dlen )
242 DNS_STATUS ret = ERROR_SUCCESS;
243 const unsigned char *pos = rr->rdata;
244 unsigned int i, size;
250 r->Data.A.IpAddress = *(DWORD *)pos;
251 *dlen = sizeof(DNS_A_DATA);
256 for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
258 r->Data.AAAA.Ip6Address.IP6Dword[i] = *(DWORD *)pos;
259 pos += sizeof(DWORD);
262 *dlen = sizeof(DNS_AAAA_DATA);
267 /* FIXME: byte order? */
268 r->Data.KEY.wFlags = *(WORD *)pos; pos += sizeof(WORD);
269 r->Data.KEY.chProtocol = *(BYTE *)pos++;
270 r->Data.KEY.chAlgorithm = *(BYTE *)pos++;
272 size = rr->rdata + rr->rdlength - pos;
274 for (i = 0; i < size; i++)
275 r->Data.KEY.Key[i] = *(BYTE *)pos++;
277 *dlen = sizeof(DNS_KEY_DATA) + (size - 1) * sizeof(BYTE);
283 r->Data.MINFO.pNameMailbox = dns_dname_from_msg( msg, pos );
284 if (!r->Data.MINFO.pNameMailbox) return ERROR_NOT_ENOUGH_MEMORY;
286 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
287 return DNS_ERROR_BAD_PACKET;
289 r->Data.MINFO.pNameErrorsMailbox = dns_dname_from_msg( msg, pos );
290 if (!r->Data.MINFO.pNameErrorsMailbox)
292 dns_free( r->Data.MINFO.pNameMailbox );
293 return ERROR_NOT_ENOUGH_MEMORY;
296 *dlen = sizeof(DNS_MINFO_DATAA);
303 r->Data.MX.wPreference = ntohs( *(WORD *)pos );
304 r->Data.MX.pNameExchange = dns_dname_from_msg( msg, pos + sizeof(WORD) );
305 if (!r->Data.MX.pNameExchange) return ERROR_NOT_ENOUGH_MEMORY;
307 *dlen = sizeof(DNS_MX_DATAA);
312 r->Data.Null.dwByteCount = rr->rdlength;
313 memcpy( r->Data.Null.Data, rr->rdata, rr->rdlength );
315 *dlen = sizeof(DNS_NULL_DATA) + rr->rdlength - 1;
327 r->Data.PTR.pNameHost = dns_dname_from_msg( msg, pos );
328 if (!r->Data.PTR.pNameHost) return ERROR_NOT_ENOUGH_MEMORY;
330 *dlen = sizeof(DNS_PTR_DATAA);
335 r->Data.SIG.pNameSigner = dns_dname_from_msg( msg, pos );
336 if (!r->Data.SIG.pNameSigner) return ERROR_NOT_ENOUGH_MEMORY;
338 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
339 return DNS_ERROR_BAD_PACKET;
341 /* FIXME: byte order? */
342 r->Data.SIG.wTypeCovered = *(WORD *)pos; pos += sizeof(WORD);
343 r->Data.SIG.chAlgorithm = *(BYTE *)pos++;
344 r->Data.SIG.chLabelCount = *(BYTE *)pos++;
345 r->Data.SIG.dwOriginalTtl = *(DWORD *)pos; pos += sizeof(DWORD);
346 r->Data.SIG.dwExpiration = *(DWORD *)pos; pos += sizeof(DWORD);
347 r->Data.SIG.dwTimeSigned = *(DWORD *)pos; pos += sizeof(DWORD);
348 r->Data.SIG.wKeyTag = *(WORD *)pos;
350 size = rr->rdata + rr->rdlength - pos;
352 for (i = 0; i < size; i++)
353 r->Data.SIG.Signature[i] = *(BYTE *)pos++;
355 *dlen = sizeof(DNS_SIG_DATAA) + (size - 1) * sizeof(BYTE);
360 r->Data.SOA.pNamePrimaryServer = dns_dname_from_msg( msg, pos );
361 if (!r->Data.SOA.pNamePrimaryServer) return ERROR_NOT_ENOUGH_MEMORY;
363 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
364 return DNS_ERROR_BAD_PACKET;
366 r->Data.SOA.pNameAdministrator = dns_dname_from_msg( msg, pos );
367 if (!r->Data.SOA.pNameAdministrator)
369 dns_free( r->Data.SOA.pNamePrimaryServer );
370 return ERROR_NOT_ENOUGH_MEMORY;
373 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
374 return DNS_ERROR_BAD_PACKET;
376 r->Data.SOA.dwSerialNo = ntohl( *(DWORD *)pos ); pos += sizeof(DWORD);
377 r->Data.SOA.dwRefresh = ntohl( *(DWORD *)pos ); pos += sizeof(DWORD);
378 r->Data.SOA.dwRetry = ntohl( *(DWORD *)pos ); pos += sizeof(DWORD);
379 r->Data.SOA.dwExpire = ntohl( *(DWORD *)pos ); pos += sizeof(DWORD);
380 r->Data.SOA.dwDefaultTtl = ntohl( *(DWORD *)pos ); pos += sizeof(DWORD);
382 *dlen = sizeof(DNS_SOA_DATAA);
387 r->Data.SRV.wPriority = ntohs( *(WORD *)pos ); pos += sizeof(WORD);
388 r->Data.SRV.wWeight = ntohs( *(WORD *)pos ); pos += sizeof(WORD);
389 r->Data.SRV.wPort = ntohs( *(WORD *)pos ); pos += sizeof(WORD);
391 r->Data.SRV.pNameTarget = dns_dname_from_msg( msg, pos );
392 if (!r->Data.SRV.pNameTarget) return ERROR_NOT_ENOUGH_MEMORY;
394 *dlen = sizeof(DNS_SRV_DATAA);
403 while (pos[0] && pos < rr->rdata + rr->rdlength)
405 r->Data.TXT.pStringArray[i] = dns_str_from_rdata( pos );
406 if (!r->Data.TXT.pStringArray[i])
408 for (--i; i >= 0; i--)
409 dns_free( r->Data.TXT.pStringArray[i] );
410 return ERROR_NOT_ENOUGH_MEMORY;
415 r->Data.TXT.dwStringCount = i;
416 *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR);
424 case 0x00f9: /* TKEY */
425 case 0xff01: /* WINS */
426 case 0xff02: /* WINSR */
428 FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
429 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
435 static DNS_STATUS dns_copy_record( ns_msg msg, ns_sect section,
436 unsigned short num, DNS_RECORDA **recp )
443 if (dns_ns_parserr( &msg, section, num, &rr ) < 0)
444 return DNS_ERROR_BAD_PACKET;
446 if (!(record = dns_zero_alloc( dns_get_record_size( &rr ) )))
447 return ERROR_NOT_ENOUGH_MEMORY;
449 record->pName = dns_strdup_u( rr.name );
453 return ERROR_NOT_ENOUGH_MEMORY;
456 record->wType = rr.type;
457 record->Flags.S.Section = section;
458 record->Flags.S.CharSet = DnsCharSetUtf8;
459 record->dwTtl = rr.ttl;
461 if ((ret = dns_copy_rdata( msg, &rr, record, &dlen )))
463 dns_free( record->pName );
467 record->wDataLength = dlen;
470 TRACE( "found %s record in %s section\n",
471 dns_type_to_str( rr.type ), dns_section_to_str( section ) );
472 return ERROR_SUCCESS;
475 /* The resolver lock must be held and res_init() must have been
476 * called before calling these three functions.
478 static DNS_STATUS dns_set_serverlist( PIP4_ARRAY addrs )
482 if (addrs->AddrCount > MAXNS)
484 WARN( "too many servers: %ld only using the first: %d\n",
485 addrs->AddrCount, MAXNS );
486 _res.nscount = MAXNS;
488 else _res.nscount = addrs->AddrCount;
490 for (i = 0; i < _res.nscount; i++)
491 _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
493 return ERROR_SUCCESS;
496 static DNS_STATUS dns_get_serverlist( PIP4_ARRAY addrs, PDWORD len )
498 unsigned int i, size;
500 size = sizeof(IP4_ARRAY) + sizeof(IP4_ADDRESS) * (_res.nscount - 1);
501 if (!addrs || *len < size)
504 return ERROR_INSUFFICIENT_BUFFER;
507 addrs->AddrCount = _res.nscount;
509 for (i = 0; i < _res.nscount; i++)
510 addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
512 return ERROR_SUCCESS;
515 static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options,
516 PDNS_RECORDA *result )
518 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
521 unsigned char answer[NS_PACKETSZ];
522 ns_sect sections[] = { ns_s_an, ns_s_ar };
525 DNS_RECORDA *record = NULL;
529 DNS_RRSET_INIT( rrset );
531 len = __res_query( name, C_IN, type, answer, sizeof(answer) );
534 ret = dns_map_h_errno( h_errno );
538 if (dns_ns_initparse( answer, len, &msg ) < 0)
540 ret = DNS_ERROR_BAD_PACKET;
544 if (ns_msg_getflag( msg, ns_f_rcode ) != ns_r_noerror)
546 ret = dns_map_error( ns_msg_getflag( msg, ns_f_rcode ) );
550 for (i = 0; i < sizeof(sections)/sizeof(sections[0]); i++)
552 for (num = 0; num < ns_msg_count( msg, sections[i] ); num++)
554 ret = dns_copy_record( msg, sections[i], num, &record );
555 if (ret != ERROR_SUCCESS) goto exit;
557 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
562 DNS_RRSET_TERMINATE( rrset );
564 if (ret != ERROR_SUCCESS)
565 DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
567 *result = (DNS_RECORDA *)rrset.pFirstRR;
572 #endif /* HAVE_RESOLV */
574 /******************************************************************************
575 * DnsQuery_A [DNSAPI.@]
578 DNS_STATUS WINAPI DnsQuery_A( PCSTR name, WORD type, DWORD options, PIP4_ARRAY servers,
579 PDNS_RECORDA *result, PVOID *reserved )
582 DNS_RECORDW *resultW;
585 TRACE( "(%s,%s,0x%08lx,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
586 options, servers, result, reserved );
588 if (!name || !result)
589 return ERROR_INVALID_PARAMETER;
591 nameW = dns_strdup_aw( name );
592 if (!nameW) return ERROR_NOT_ENOUGH_MEMORY;
594 status = DnsQuery_W( nameW, type, options, servers, &resultW, reserved );
596 if (status == ERROR_SUCCESS)
598 *result = (DNS_RECORDA *)DnsRecordSetCopyEx(
599 (DNS_RECORD *)resultW, DnsCharSetUnicode, DnsCharSetAnsi );
601 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
602 DnsRecordListFree( (DNS_RECORD *)resultW, DnsFreeRecordList );
609 /******************************************************************************
610 * DnsQuery_UTF8 [DNSAPI.@]
613 DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PIP4_ARRAY servers,
614 PDNS_RECORDA *result, PVOID *reserved )
616 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
619 TRACE( "(%s,%s,0x%08lx,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
620 options, servers, result, reserved );
622 if (!name || !result)
623 return ERROR_INVALID_PARAMETER;
628 _res.options |= dns_map_options( options );
630 if (servers && (ret = dns_set_serverlist( servers )))
636 ret = dns_do_query( name, type, options, result );
644 /******************************************************************************
645 * DnsQuery_W [DNSAPI.@]
648 DNS_STATUS WINAPI DnsQuery_W( PCWSTR name, WORD type, DWORD options, PIP4_ARRAY servers,
649 PDNS_RECORDW *result, PVOID *reserved )
652 DNS_RECORDA *resultA;
655 TRACE( "(%s,%s,0x%08lx,%p,%p,%p)\n", debugstr_w(name), dns_type_to_str( type ),
656 options, servers, result, reserved );
658 if (!name || !result)
659 return ERROR_INVALID_PARAMETER;
661 nameU = dns_strdup_wu( name );
662 if (!nameU) return ERROR_NOT_ENOUGH_MEMORY;
664 status = DnsQuery_UTF8( nameU, type, options, servers, &resultA, reserved );
666 if (status == ERROR_SUCCESS)
668 *result = (DNS_RECORDW *)DnsRecordSetCopyEx(
669 (DNS_RECORD *)resultA, DnsCharSetUtf8, DnsCharSetUnicode );
671 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
672 DnsRecordListFree( (DNS_RECORD *)resultA, DnsFreeRecordList );
679 static DNS_STATUS dns_get_hostname_a( COMPUTER_NAME_FORMAT format,
680 LPSTR buffer, PDWORD len )
683 DWORD size = sizeof(name);
685 if (!GetComputerNameExA( format, name, &size ))
686 return DNS_ERROR_NAME_DOES_NOT_EXIST;
688 if (!buffer || (size = lstrlenA( name ) + 1) > *len)
691 return ERROR_INSUFFICIENT_BUFFER;
694 lstrcpyA( buffer, name );
695 return ERROR_SUCCESS;
698 static DNS_STATUS dns_get_hostname_w( COMPUTER_NAME_FORMAT format,
699 LPWSTR buffer, PDWORD len )
702 DWORD size = sizeof(name);
704 if (!GetComputerNameExW( format, name, &size ))
705 return DNS_ERROR_NAME_DOES_NOT_EXIST;
707 if (!buffer || (size = lstrlenW( name ) + 1) > *len)
710 return ERROR_INSUFFICIENT_BUFFER;
713 lstrcpyW( buffer, name );
714 return ERROR_SUCCESS;
717 /******************************************************************************
718 * DnsQueryConfig [DNSAPI.@]
721 DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PWSTR adapter,
722 PVOID reserved, PVOID buffer, PDWORD len )
724 DNS_STATUS ret = ERROR_INVALID_PARAMETER;
726 TRACE( "(%d,0x%08lx,%s,%p,%p,%p)\n", config, flag, debugstr_w(adapter),
727 reserved, buffer, len );
729 if (!len) return ERROR_INVALID_PARAMETER;
733 case DnsConfigDnsServerList:
739 ret = dns_get_serverlist( (IP4_ARRAY *)buffer, len );
744 WARN( "compiled without resolver support\n" );
748 case DnsConfigHostName_A:
749 case DnsConfigHostName_UTF8:
750 return dns_get_hostname_a( ComputerNameDnsHostname, buffer, len );
752 case DnsConfigFullHostName_A:
753 case DnsConfigFullHostName_UTF8:
754 return dns_get_hostname_a( ComputerNameDnsFullyQualified, buffer, len );
756 case DnsConfigPrimaryDomainName_A:
757 case DnsConfigPrimaryDomainName_UTF8:
758 return dns_get_hostname_a( ComputerNameDnsDomain, buffer, len );
760 case DnsConfigHostName_W:
761 return dns_get_hostname_w( ComputerNameDnsHostname, buffer, len );
763 case DnsConfigFullHostName_W:
764 return dns_get_hostname_w( ComputerNameDnsFullyQualified, buffer, len );
766 case DnsConfigPrimaryDomainName_W:
767 return dns_get_hostname_w( ComputerNameDnsDomain, buffer, len );
769 case DnsConfigAdapterDomainName_A:
770 case DnsConfigAdapterDomainName_W:
771 case DnsConfigAdapterDomainName_UTF8:
772 case DnsConfigSearchList:
773 case DnsConfigAdapterInfo:
774 case DnsConfigPrimaryHostNameRegistrationEnabled:
775 case DnsConfigAdapterHostNameRegistrationEnabled:
776 case DnsConfigAddressRegistrationMaxCount:
777 FIXME( "unimplemented config type %d\n", config );
781 WARN( "unknown config type: %d\n", config );