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
30 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi
);
35 #define DEFAULT_TTL 1200
37 static DNS_STATUS
do_query_netbios( PCSTR name
, DNS_RECORDA
**recp
)
42 FIND_NAME_BUFFER
*buffer
;
43 FIND_NAME_HEADER
*header
;
44 DNS_RECORDA
*record
= NULL
;
46 DNS_STATUS status
= ERROR_INVALID_NAME
;
49 if (len
>= NCBNAMSZ
) return DNS_ERROR_RCODE_NAME_ERROR
;
51 DNS_RRSET_INIT( rrset
);
53 memset( &ncb
, 0, sizeof(ncb
) );
54 ncb
.ncb_command
= NCBFINDNAME
;
56 memset( ncb
.ncb_callname
, ' ', sizeof(ncb
.ncb_callname
) );
57 memcpy( ncb
.ncb_callname
, name
, len
);
58 ncb
.ncb_callname
[NCBNAMSZ
- 1] = '\0';
60 ret
= Netbios( &ncb
);
61 if (ret
!= NRC_GOODRET
) return ERROR_INVALID_NAME
;
63 header
= (FIND_NAME_HEADER
*)ncb
.ncb_buffer
;
64 buffer
= (FIND_NAME_BUFFER
*)((char *)header
+ sizeof(FIND_NAME_HEADER
));
66 for (i
= 0; i
< header
->node_count
; i
++)
68 record
= calloc( 1, sizeof(DNS_RECORDA
) );
71 status
= ERROR_NOT_ENOUGH_MEMORY
;
76 record
->pName
= strdup( name
);
79 status
= ERROR_NOT_ENOUGH_MEMORY
;
84 record
->wType
= DNS_TYPE_A
;
85 record
->Flags
.S
.Section
= DnsSectionAnswer
;
86 record
->Flags
.S
.CharSet
= DnsCharSetUtf8
;
87 record
->dwTtl
= DEFAULT_TTL
;
89 /* FIXME: network byte order? */
90 record
->Data
.A
.IpAddress
= *(DWORD
*)((char *)buffer
[i
].destination_addr
+ 2);
92 DNS_RRSET_ADD( rrset
, (DNS_RECORD
*)record
);
95 status
= ERROR_SUCCESS
;
98 DNS_RRSET_TERMINATE( rrset
);
100 if (status
!= ERROR_SUCCESS
)
101 DnsRecordListFree( rrset
.pFirstRR
, DnsFreeRecordList
);
103 *recp
= (DNS_RECORDA
*)rrset
.pFirstRR
;
108 static const char *debugstr_query_request(const DNS_QUERY_REQUEST
*req
)
110 if (!req
) return "(null)";
111 return wine_dbg_sprintf("{%lu %s %s %I64x %p %lu %p %p}", req
->Version
,
112 debugstr_w(req
->QueryName
), debugstr_type(req
->QueryType
),
113 req
->QueryOptions
, req
->pDnsServerList
, req
->InterfaceIndex
,
114 req
->pQueryCompletionCallback
, req
->pQueryContext
);
117 /******************************************************************************
118 * DnsQueryEx [DNSAPI.@]
121 DNS_STATUS WINAPI
DnsQueryEx(DNS_QUERY_REQUEST
*request
, DNS_QUERY_RESULT
*result
, DNS_QUERY_CANCEL
*cancel
)
123 FIXME("(%s, %p, %p)\n", debugstr_query_request(request
), result
, cancel
);
124 return DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
127 /******************************************************************************
128 * DnsQuery_A [DNSAPI.@]
131 DNS_STATUS WINAPI
DnsQuery_A( const char *name
, WORD type
, DWORD options
, void *servers
, DNS_RECORDA
**result
,
135 DNS_RECORDW
*resultW
;
138 TRACE( "(%s, %s, %#lx, %p, %p, %p)\n", debugstr_a(name
), debugstr_type( type
),
139 options
, servers
, result
, reserved
);
141 if (!name
|| !result
)
142 return ERROR_INVALID_PARAMETER
;
144 nameW
= strdup_aw( name
);
145 if (!nameW
) return ERROR_NOT_ENOUGH_MEMORY
;
147 status
= DnsQuery_W( nameW
, type
, options
, servers
, &resultW
, reserved
);
149 if (status
== ERROR_SUCCESS
)
151 *result
= (DNS_RECORDA
*)DnsRecordSetCopyEx(
152 (DNS_RECORD
*)resultW
, DnsCharSetUnicode
, DnsCharSetAnsi
);
154 if (!*result
) status
= ERROR_NOT_ENOUGH_MEMORY
;
155 DnsRecordListFree( (DNS_RECORD
*)resultW
, DnsFreeRecordList
);
162 /******************************************************************************
163 * DnsQuery_UTF8 [DNSAPI.@]
166 DNS_STATUS WINAPI
DnsQuery_UTF8( const char *name
, WORD type
, DWORD options
, void *servers
, DNS_RECORDA
**result
,
169 DNS_STATUS ret
= DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
170 unsigned char answer
[4096];
171 DWORD len
= sizeof(answer
);
172 struct query_params query_params
= { name
, type
, options
, answer
, &len
};
174 TRACE( "(%s, %s, %#lx, %p, %p, %p)\n", debugstr_a(name
), debugstr_type( type
),
175 options
, servers
, result
, reserved
);
177 if (!name
|| !result
)
178 return ERROR_INVALID_PARAMETER
;
180 if ((ret
= RESOLV_CALL( set_serverlist
, servers
))) return ret
;
182 ret
= RESOLV_CALL( query
, &query_params
);
185 DNS_MESSAGE_BUFFER
*buffer
= (DNS_MESSAGE_BUFFER
*)answer
;
187 if (len
< sizeof(buffer
->MessageHead
)) return DNS_ERROR_BAD_PACKET
;
188 DNS_BYTE_FLIP_HEADER_COUNTS( &buffer
->MessageHead
);
189 switch (buffer
->MessageHead
.ResponseCode
)
191 case DNS_RCODE_NOERROR
: ret
= DnsExtractRecordsFromMessage_UTF8( buffer
, len
, result
); break;
192 case DNS_RCODE_FORMERR
: ret
= DNS_ERROR_RCODE_FORMAT_ERROR
; break;
193 case DNS_RCODE_SERVFAIL
: ret
= DNS_ERROR_RCODE_SERVER_FAILURE
; break;
194 case DNS_RCODE_NXDOMAIN
: ret
= DNS_ERROR_RCODE_NAME_ERROR
; break;
195 case DNS_RCODE_NOTIMPL
: ret
= DNS_ERROR_RCODE_NOT_IMPLEMENTED
; break;
196 case DNS_RCODE_REFUSED
: ret
= DNS_ERROR_RCODE_REFUSED
; break;
197 case DNS_RCODE_YXDOMAIN
: ret
= DNS_ERROR_RCODE_YXDOMAIN
; break;
198 case DNS_RCODE_YXRRSET
: ret
= DNS_ERROR_RCODE_YXRRSET
; break;
199 case DNS_RCODE_NXRRSET
: ret
= DNS_ERROR_RCODE_NXRRSET
; break;
200 case DNS_RCODE_NOTAUTH
: ret
= DNS_ERROR_RCODE_NOTAUTH
; break;
201 case DNS_RCODE_NOTZONE
: ret
= DNS_ERROR_RCODE_NOTZONE
; break;
202 default: ret
= DNS_ERROR_RCODE_NOT_IMPLEMENTED
; break;
206 if (ret
== DNS_ERROR_RCODE_NAME_ERROR
&& type
== DNS_TYPE_A
&&
207 !(options
& DNS_QUERY_NO_NETBT
))
209 TRACE( "dns lookup failed, trying netbios query\n" );
210 ret
= do_query_netbios( name
, result
);
216 /******************************************************************************
217 * DnsQuery_W [DNSAPI.@]
220 DNS_STATUS WINAPI
DnsQuery_W( const WCHAR
*name
, WORD type
, DWORD options
, void *servers
, DNS_RECORDW
**result
,
224 DNS_RECORDA
*resultA
;
227 TRACE( "(%s, %s, %#lx, %p, %p, %p)\n", debugstr_w(name
), debugstr_type( type
),
228 options
, servers
, result
, reserved
);
230 if (!name
|| !result
)
231 return ERROR_INVALID_PARAMETER
;
233 nameU
= strdup_wu( name
);
234 if (!nameU
) return ERROR_NOT_ENOUGH_MEMORY
;
236 status
= DnsQuery_UTF8( nameU
, type
, options
, servers
, &resultA
, reserved
);
238 if (status
== ERROR_SUCCESS
)
240 *result
= (DNS_RECORDW
*)DnsRecordSetCopyEx(
241 (DNS_RECORD
*)resultA
, DnsCharSetUtf8
, DnsCharSetUnicode
);
243 if (!*result
) status
= ERROR_NOT_ENOUGH_MEMORY
;
244 DnsRecordListFree( (DNS_RECORD
*)resultA
, DnsFreeRecordList
);
251 static DNS_STATUS
get_hostname_a( COMPUTER_NAME_FORMAT format
, PSTR buffer
, PDWORD len
)
254 DWORD size
= ARRAY_SIZE(name
);
256 if (!GetComputerNameExA( format
, name
, &size
))
257 return DNS_ERROR_NAME_DOES_NOT_EXIST
;
259 if (!buffer
|| (size
= lstrlenA( name
) + 1) > *len
)
262 return ERROR_INSUFFICIENT_BUFFER
;
265 lstrcpyA( buffer
, name
);
266 return ERROR_SUCCESS
;
269 static DNS_STATUS
get_hostname_w( COMPUTER_NAME_FORMAT format
, PWSTR buffer
, PDWORD len
)
272 DWORD size
= ARRAY_SIZE(name
);
274 if (!GetComputerNameExW( format
, name
, &size
))
275 return DNS_ERROR_NAME_DOES_NOT_EXIST
;
277 if (!buffer
|| (size
= lstrlenW( name
) + 1) > *len
)
280 return ERROR_INSUFFICIENT_BUFFER
;
283 lstrcpyW( buffer
, name
);
284 return ERROR_SUCCESS
;
287 static DNS_STATUS
get_dns_server_list( IP4_ARRAY
*out
, DWORD
*len
)
289 char buf
[FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[3])];
290 DNS_ADDR_ARRAY
*servers
= (DNS_ADDR_ARRAY
*)buf
;
291 DWORD ret
, needed
, i
, num
, array_len
= sizeof(buf
);
292 struct get_serverlist_params params
= { AF_INET
, servers
, &array_len
};
295 ret
= RESOLV_CALL( get_serverlist
, ¶ms
);
296 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) goto err
;
297 num
= (array_len
- FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[0])) / sizeof(DNS_ADDR
);
298 needed
= FIELD_OFFSET(IP4_ARRAY
, AddrArray
[num
]);
299 if (!out
|| *len
< needed
)
302 ret
= !out
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
307 if ((char *)servers
!= buf
) free( servers
);
308 servers
= malloc( array_len
);
311 ret
= ERROR_NOT_ENOUGH_MEMORY
;
316 out
->AddrCount
= num
;
317 for (i
= 0; i
< num
; i
++)
318 out
->AddrArray
[i
] = ((SOCKADDR_IN
*)servers
->AddrArray
[i
].MaxSa
)->sin_addr
.s_addr
;
323 if ((char *)servers
!= buf
) free( servers
);
327 /******************************************************************************
328 * DnsQueryConfig [DNSAPI.@]
331 DNS_STATUS WINAPI
DnsQueryConfig( DNS_CONFIG_TYPE config
, DWORD flag
, const WCHAR
*adapter
, void *reserved
,
332 void *buffer
, DWORD
*len
)
334 DNS_STATUS ret
= ERROR_INVALID_PARAMETER
;
336 TRACE( "(%d, %#lx, %s, %p, %p, %p)\n", config
, flag
, debugstr_w(adapter
), reserved
, buffer
, len
);
338 if (!len
) return ERROR_INVALID_PARAMETER
;
342 case DnsConfigDnsServerList
:
343 return get_dns_server_list( buffer
, len
);
345 case DnsConfigHostName_A
:
346 case DnsConfigHostName_UTF8
:
347 return get_hostname_a( ComputerNameDnsHostname
, buffer
, len
);
349 case DnsConfigFullHostName_A
:
350 case DnsConfigFullHostName_UTF8
:
351 return get_hostname_a( ComputerNameDnsFullyQualified
, buffer
, len
);
353 case DnsConfigPrimaryDomainName_A
:
354 case DnsConfigPrimaryDomainName_UTF8
:
355 return get_hostname_a( ComputerNameDnsDomain
, buffer
, len
);
357 case DnsConfigHostName_W
:
358 return get_hostname_w( ComputerNameDnsHostname
, buffer
, len
);
360 case DnsConfigFullHostName_W
:
361 return get_hostname_w( ComputerNameDnsFullyQualified
, buffer
, len
);
363 case DnsConfigPrimaryDomainName_W
:
364 return get_hostname_w( ComputerNameDnsDomain
, buffer
, len
);
366 case DnsConfigAdapterDomainName_A
:
367 case DnsConfigAdapterDomainName_W
:
368 case DnsConfigAdapterDomainName_UTF8
:
369 case DnsConfigAdapterInfo
:
370 case DnsConfigPrimaryHostNameRegistrationEnabled
:
371 case DnsConfigAdapterHostNameRegistrationEnabled
:
372 case DnsConfigAddressRegistrationMaxCount
:
373 FIXME( "unimplemented config type %d\n", config
);
376 case DnsConfigDnsServersUnspec
:
378 struct get_serverlist_params params
= { AF_UNSPEC
, buffer
, len
};
379 return RESOLV_CALL( get_serverlist
, ¶ms
);
381 case DnsConfigDnsServersIpv4
:
383 struct get_serverlist_params params
= { AF_INET
, buffer
, len
};
384 return RESOLV_CALL( get_serverlist
, ¶ms
);
386 case DnsConfigDnsServersIpv6
:
388 struct get_serverlist_params params
= { AF_INET6
, buffer
, len
};
389 return RESOLV_CALL( get_serverlist
, ¶ms
);
391 /* Windows does not implement this, but we need it in iphlpapi. */
392 case DnsConfigSearchList
:
394 struct get_searchlist_params params
= { buffer
, len
};
395 return RESOLV_CALL( get_searchlist
, ¶ms
);
398 WARN( "unknown config type: %d\n", config
);