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
;
83 record
->wType
= DNS_TYPE_A
;
84 record
->Flags
.S
.Section
= DnsSectionAnswer
;
85 record
->Flags
.S
.CharSet
= DnsCharSetUtf8
;
86 record
->dwTtl
= DEFAULT_TTL
;
88 /* FIXME: network byte order? */
89 record
->Data
.A
.IpAddress
= *(DWORD
*)((char *)buffer
[i
].destination_addr
+ 2);
91 DNS_RRSET_ADD( rrset
, (DNS_RECORD
*)record
);
94 status
= ERROR_SUCCESS
;
97 DNS_RRSET_TERMINATE( rrset
);
99 if (status
!= ERROR_SUCCESS
)
100 DnsRecordListFree( rrset
.pFirstRR
, DnsFreeRecordList
);
102 *recp
= (DNS_RECORDA
*)rrset
.pFirstRR
;
107 static const char *debugstr_query_request(const DNS_QUERY_REQUEST
*req
)
109 if (!req
) return "(null)";
110 return wine_dbg_sprintf("{%lu %s %s %I64x %p %lu %p %p}", req
->Version
,
111 debugstr_w(req
->QueryName
), debugstr_type(req
->QueryType
),
112 req
->QueryOptions
, req
->pDnsServerList
, req
->InterfaceIndex
,
113 req
->pQueryCompletionCallback
, req
->pQueryContext
);
116 /******************************************************************************
117 * DnsQueryEx [DNSAPI.@]
120 DNS_STATUS WINAPI
DnsQueryEx(DNS_QUERY_REQUEST
*request
, DNS_QUERY_RESULT
*result
, DNS_QUERY_CANCEL
*cancel
)
122 FIXME("(%s, %p, %p)\n", debugstr_query_request(request
), result
, cancel
);
123 return DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
126 /******************************************************************************
127 * DnsQuery_A [DNSAPI.@]
130 DNS_STATUS WINAPI
DnsQuery_A( const char *name
, WORD type
, DWORD options
, void *servers
, DNS_RECORDA
**result
,
134 DNS_RECORDW
*resultW
;
137 TRACE( "(%s, %s, %#lx, %p, %p, %p)\n", debugstr_a(name
), debugstr_type( type
),
138 options
, servers
, result
, reserved
);
140 if (!name
|| !result
)
141 return ERROR_INVALID_PARAMETER
;
143 nameW
= strdup_aw( name
);
144 if (!nameW
) return ERROR_NOT_ENOUGH_MEMORY
;
146 status
= DnsQuery_W( nameW
, type
, options
, servers
, &resultW
, reserved
);
148 if (status
== ERROR_SUCCESS
)
150 *result
= (DNS_RECORDA
*)DnsRecordSetCopyEx(
151 (DNS_RECORD
*)resultW
, DnsCharSetUnicode
, DnsCharSetAnsi
);
153 if (!*result
) status
= ERROR_NOT_ENOUGH_MEMORY
;
154 DnsRecordListFree( (DNS_RECORD
*)resultW
, DnsFreeRecordList
);
161 /******************************************************************************
162 * DnsQuery_UTF8 [DNSAPI.@]
165 DNS_STATUS WINAPI
DnsQuery_UTF8( const char *name
, WORD type
, DWORD options
, void *servers
, DNS_RECORDA
**result
,
168 DNS_STATUS ret
= DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
169 unsigned char answer
[4096];
170 DWORD len
= sizeof(answer
);
171 struct query_params query_params
= { name
, type
, options
, answer
, &len
};
173 TRACE( "(%s, %s, %#lx, %p, %p, %p)\n", debugstr_a(name
), debugstr_type( type
),
174 options
, servers
, result
, reserved
);
176 if (!name
|| !result
)
177 return ERROR_INVALID_PARAMETER
;
179 if ((ret
= RESOLV_CALL( set_serverlist
, servers
))) return ret
;
181 ret
= RESOLV_CALL( query
, &query_params
);
184 DNS_MESSAGE_BUFFER
*buffer
= (DNS_MESSAGE_BUFFER
*)answer
;
186 if (len
< sizeof(buffer
->MessageHead
)) return DNS_ERROR_BAD_PACKET
;
187 DNS_BYTE_FLIP_HEADER_COUNTS( &buffer
->MessageHead
);
188 switch (buffer
->MessageHead
.ResponseCode
)
190 case DNS_RCODE_NOERROR
: ret
= DnsExtractRecordsFromMessage_UTF8( buffer
, len
, result
); break;
191 case DNS_RCODE_FORMERR
: ret
= DNS_ERROR_RCODE_FORMAT_ERROR
; break;
192 case DNS_RCODE_SERVFAIL
: ret
= DNS_ERROR_RCODE_SERVER_FAILURE
; break;
193 case DNS_RCODE_NXDOMAIN
: ret
= DNS_ERROR_RCODE_NAME_ERROR
; break;
194 case DNS_RCODE_NOTIMPL
: ret
= DNS_ERROR_RCODE_NOT_IMPLEMENTED
; break;
195 case DNS_RCODE_REFUSED
: ret
= DNS_ERROR_RCODE_REFUSED
; break;
196 case DNS_RCODE_YXDOMAIN
: ret
= DNS_ERROR_RCODE_YXDOMAIN
; break;
197 case DNS_RCODE_YXRRSET
: ret
= DNS_ERROR_RCODE_YXRRSET
; break;
198 case DNS_RCODE_NXRRSET
: ret
= DNS_ERROR_RCODE_NXRRSET
; break;
199 case DNS_RCODE_NOTAUTH
: ret
= DNS_ERROR_RCODE_NOTAUTH
; break;
200 case DNS_RCODE_NOTZONE
: ret
= DNS_ERROR_RCODE_NOTZONE
; break;
201 default: ret
= DNS_ERROR_RCODE_NOT_IMPLEMENTED
; break;
205 if (ret
== DNS_ERROR_RCODE_NAME_ERROR
&& type
== DNS_TYPE_A
&&
206 !(options
& DNS_QUERY_NO_NETBT
))
208 TRACE( "dns lookup failed, trying netbios query\n" );
209 ret
= do_query_netbios( name
, result
);
215 /******************************************************************************
216 * DnsQuery_W [DNSAPI.@]
219 DNS_STATUS WINAPI
DnsQuery_W( const WCHAR
*name
, WORD type
, DWORD options
, void *servers
, DNS_RECORDW
**result
,
223 DNS_RECORDA
*resultA
;
226 TRACE( "(%s, %s, %#lx, %p, %p, %p)\n", debugstr_w(name
), debugstr_type( type
),
227 options
, servers
, result
, reserved
);
229 if (!name
|| !result
)
230 return ERROR_INVALID_PARAMETER
;
232 nameU
= strdup_wu( name
);
233 if (!nameU
) return ERROR_NOT_ENOUGH_MEMORY
;
235 status
= DnsQuery_UTF8( nameU
, type
, options
, servers
, &resultA
, reserved
);
237 if (status
== ERROR_SUCCESS
)
239 *result
= (DNS_RECORDW
*)DnsRecordSetCopyEx(
240 (DNS_RECORD
*)resultA
, DnsCharSetUtf8
, DnsCharSetUnicode
);
242 if (!*result
) status
= ERROR_NOT_ENOUGH_MEMORY
;
243 DnsRecordListFree( (DNS_RECORD
*)resultA
, DnsFreeRecordList
);
250 static DNS_STATUS
get_hostname_a( COMPUTER_NAME_FORMAT format
, PSTR buffer
, PDWORD len
)
253 DWORD size
= ARRAY_SIZE(name
);
255 if (!GetComputerNameExA( format
, name
, &size
))
256 return DNS_ERROR_NAME_DOES_NOT_EXIST
;
258 if (!buffer
|| (size
= lstrlenA( name
) + 1) > *len
)
261 return ERROR_INSUFFICIENT_BUFFER
;
264 lstrcpyA( buffer
, name
);
265 return ERROR_SUCCESS
;
268 static DNS_STATUS
get_hostname_w( COMPUTER_NAME_FORMAT format
, PWSTR buffer
, PDWORD len
)
271 DWORD size
= ARRAY_SIZE(name
);
273 if (!GetComputerNameExW( format
, name
, &size
))
274 return DNS_ERROR_NAME_DOES_NOT_EXIST
;
276 if (!buffer
|| (size
= lstrlenW( name
) + 1) > *len
)
279 return ERROR_INSUFFICIENT_BUFFER
;
282 lstrcpyW( buffer
, name
);
283 return ERROR_SUCCESS
;
286 static DNS_STATUS
get_dns_server_list( IP4_ARRAY
*out
, DWORD
*len
)
288 char buf
[FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[3])];
289 DNS_ADDR_ARRAY
*servers
= (DNS_ADDR_ARRAY
*)buf
;
290 DWORD ret
, needed
, i
, num
, array_len
= sizeof(buf
);
291 struct get_serverlist_params params
= { AF_INET
, servers
, &array_len
};
294 ret
= RESOLV_CALL( get_serverlist
, ¶ms
);
295 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) goto err
;
296 num
= (array_len
- FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[0])) / sizeof(DNS_ADDR
);
297 needed
= FIELD_OFFSET(IP4_ARRAY
, AddrArray
[num
]);
298 if (!out
|| *len
< needed
)
301 ret
= !out
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
306 if ((char *)servers
!= buf
) free( servers
);
307 servers
= malloc( array_len
);
310 ret
= ERROR_NOT_ENOUGH_MEMORY
;
315 out
->AddrCount
= num
;
316 for (i
= 0; i
< num
; i
++)
317 out
->AddrArray
[i
] = ((SOCKADDR_IN
*)servers
->AddrArray
[i
].MaxSa
)->sin_addr
.s_addr
;
322 if ((char *)servers
!= buf
) free( servers
);
326 /******************************************************************************
327 * DnsQueryConfig [DNSAPI.@]
330 DNS_STATUS WINAPI
DnsQueryConfig( DNS_CONFIG_TYPE config
, DWORD flag
, const WCHAR
*adapter
, void *reserved
,
331 void *buffer
, DWORD
*len
)
333 DNS_STATUS ret
= ERROR_INVALID_PARAMETER
;
335 TRACE( "(%d, %#lx, %s, %p, %p, %p)\n", config
, flag
, debugstr_w(adapter
), reserved
, buffer
, len
);
337 if (!len
) return ERROR_INVALID_PARAMETER
;
341 case DnsConfigDnsServerList
:
342 return get_dns_server_list( buffer
, len
);
344 case DnsConfigHostName_A
:
345 case DnsConfigHostName_UTF8
:
346 return get_hostname_a( ComputerNameDnsHostname
, buffer
, len
);
348 case DnsConfigFullHostName_A
:
349 case DnsConfigFullHostName_UTF8
:
350 return get_hostname_a( ComputerNameDnsFullyQualified
, buffer
, len
);
352 case DnsConfigPrimaryDomainName_A
:
353 case DnsConfigPrimaryDomainName_UTF8
:
354 return get_hostname_a( ComputerNameDnsDomain
, buffer
, len
);
356 case DnsConfigHostName_W
:
357 return get_hostname_w( ComputerNameDnsHostname
, buffer
, len
);
359 case DnsConfigFullHostName_W
:
360 return get_hostname_w( ComputerNameDnsFullyQualified
, buffer
, len
);
362 case DnsConfigPrimaryDomainName_W
:
363 return get_hostname_w( ComputerNameDnsDomain
, buffer
, len
);
365 case DnsConfigAdapterDomainName_A
:
366 case DnsConfigAdapterDomainName_W
:
367 case DnsConfigAdapterDomainName_UTF8
:
368 case DnsConfigAdapterInfo
:
369 case DnsConfigPrimaryHostNameRegistrationEnabled
:
370 case DnsConfigAdapterHostNameRegistrationEnabled
:
371 case DnsConfigAddressRegistrationMaxCount
:
372 FIXME( "unimplemented config type %d\n", config
);
375 case DnsConfigDnsServersUnspec
:
377 struct get_serverlist_params params
= { AF_UNSPEC
, buffer
, len
};
378 return RESOLV_CALL( get_serverlist
, ¶ms
);
380 case DnsConfigDnsServersIpv4
:
382 struct get_serverlist_params params
= { AF_INET
, buffer
, len
};
383 return RESOLV_CALL( get_serverlist
, ¶ms
);
385 case DnsConfigDnsServersIpv6
:
387 struct get_serverlist_params params
= { AF_INET6
, buffer
, len
};
388 return RESOLV_CALL( get_serverlist
, ¶ms
);
390 /* Windows does not implement this, but we need it in iphlpapi. */
391 case DnsConfigSearchList
:
393 struct get_searchlist_params params
= { buffer
, len
};
394 return RESOLV_CALL( get_searchlist
, ¶ms
);
397 WARN( "unknown config type: %d\n", config
);