2 * Unix interface for libresolv
4 * Copyright 2021 Hans Leidekker for CodeWeavers
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
32 #include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
37 #ifdef HAVE_ARPA_NAMESER_H
38 # include <arpa/nameser.h>
48 #define WIN32_NO_STATUS
57 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi
);
62 /* call res_init() just once because of a bug in Mac OS X 10.4 */
63 /* call once per thread on systems that have per-thread _res */
64 static void init_resolver( void )
66 if (!(_res
.options
& RES_INIT
)) res_init();
69 static unsigned long map_options( DWORD options
)
71 unsigned long ret
= 0;
73 if (options
== DNS_QUERY_STANDARD
)
76 if (options
& DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE
)
78 if (options
& DNS_QUERY_USE_TCP_ONLY
)
80 if (options
& DNS_QUERY_NO_RECURSION
)
82 if (options
& DNS_QUERY_NO_LOCAL_NAME
)
84 if (options
& DNS_QUERY_NO_HOSTS_FILE
)
86 if (options
& DNS_QUERY_TREAT_AS_FQDN
)
89 if (options
& DNS_QUERY_DONT_RESET_TTL_VALUES
)
90 FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
91 if (options
& DNS_QUERY_RESERVED
)
92 FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
93 if (options
& DNS_QUERY_WIRE_ONLY
)
94 FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
95 if (options
& DNS_QUERY_NO_WIRE_QUERY
)
96 FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
97 if (options
& DNS_QUERY_BYPASS_CACHE
)
98 FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
99 if (options
& DNS_QUERY_RETURN_MESSAGE
)
100 FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
102 if (options
& DNS_QUERY_NO_NETBT
)
103 TRACE( "netbios query disabled\n" );
108 static DNS_STATUS
map_h_errno( int error
)
113 case HOST_NOT_FOUND
: return DNS_ERROR_RCODE_NAME_ERROR
;
114 case TRY_AGAIN
: return DNS_ERROR_RCODE_SERVER_FAILURE
;
115 case NO_RECOVERY
: return DNS_ERROR_RCODE_REFUSED
;
116 #ifdef NETDB_INTERNAL
117 case NETDB_INTERNAL
: return DNS_ERROR_RCODE
;
120 FIXME( "unmapped error code: %d\n", error
);
121 return DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
125 static NTSTATUS
resolv_get_searchlist( void *args
)
127 const struct get_searchlist_params
*params
= args
;
128 DNS_TXT_DATAW
*list
= params
->list
;
129 DWORD i
, needed
, str_needed
= 0;
134 for (i
= 0; i
< MAXDNSRCH
+ 1 && _res
.dnsrch
[i
]; i
++)
135 str_needed
+= (strlen(_res
.dnsrch
[i
]) + 1) * sizeof(WCHAR
);
137 needed
= FIELD_OFFSET(DNS_TXT_DATAW
, pStringArray
[i
]) + str_needed
;
139 if (!list
|| *params
->len
< needed
)
141 *params
->len
= needed
;
142 return !list
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
145 *params
->len
= needed
;
146 list
->dwStringCount
= i
;
148 ptr
= (char *)(list
->pStringArray
+ i
);
149 end
= ptr
+ str_needed
;
150 for (i
= 0; i
< MAXDNSRCH
+ 1 && _res
.dnsrch
[i
]; i
++)
152 list
->pStringArray
[i
] = (WCHAR
*)ptr
;
153 ptr
+= ntdll_umbstowcs( _res
.dnsrch
[i
], strlen(_res
.dnsrch
[i
]) + 1,
154 list
->pStringArray
[i
], end
- ptr
);
156 return ERROR_SUCCESS
;
160 static inline int filter( unsigned short sin_family
, USHORT family
)
162 if (sin_family
!= AF_INET
&& sin_family
!= AF_INET6
) return TRUE
;
163 if (sin_family
== AF_INET6
&& family
== WS_AF_INET
) return TRUE
;
164 if (sin_family
== AF_INET
&& family
== WS_AF_INET6
) return TRUE
;
169 #ifdef HAVE_RES_GETSERVERS
171 static NTSTATUS
resolv_get_serverlist( void *args
)
173 const struct get_serverlist_params
*params
= args
;
174 DNS_ADDR_ARRAY
*addrs
= params
->addrs
;
175 struct __res_state
*state
= &_res
;
176 DWORD i
, found
, total
, needed
;
177 union res_sockaddr_union
*buf
;
181 total
= res_getservers( state
, NULL
, 0 );
182 if (!total
) return DNS_ERROR_NO_DNS_SERVERS
;
184 if (!addrs
&& params
->family
!= WS_AF_INET
&& params
->family
!= WS_AF_INET6
)
186 *params
->len
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[total
]);
187 return ERROR_SUCCESS
;
190 buf
= malloc( total
* sizeof(union res_sockaddr_union
) );
191 if (!buf
) return ERROR_NOT_ENOUGH_MEMORY
;
193 total
= res_getservers( state
, buf
, total
);
195 for (i
= 0, found
= 0; i
< total
; i
++)
197 if (filter( buf
[i
].sin
.sin_family
, params
->family
)) continue;
200 if (!found
) return DNS_ERROR_NO_DNS_SERVERS
;
202 needed
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[found
]);
203 if (!addrs
|| *params
->len
< needed
)
205 *params
->len
= needed
;
206 return !addrs
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
208 *params
->len
= needed
;
209 memset( addrs
, 0, needed
);
210 addrs
->AddrCount
= addrs
->MaxCount
= found
;
212 for (i
= 0, found
= 0; i
< total
; i
++)
214 if (filter( buf
[i
].sin
.sin_family
, params
->family
)) continue;
216 if (buf
[i
].sin6
.sin6_family
== AF_INET6
)
218 SOCKADDR_IN6
*sa
= (SOCKADDR_IN6
*)addrs
->AddrArray
[found
].MaxSa
;
219 sa
->sin6_family
= WS_AF_INET6
;
220 memcpy( &sa
->sin6_addr
, &buf
[i
].sin6
.sin6_addr
, sizeof(sa
->sin6_addr
) );
221 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
225 SOCKADDR_IN
*sa
= (SOCKADDR_IN
*)addrs
->AddrArray
[found
].MaxSa
;
226 sa
->sin_family
= WS_AF_INET
;
227 sa
->sin_addr
.WS_s_addr
= buf
[i
].sin
.sin_addr
.s_addr
;
228 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
234 return ERROR_SUCCESS
;
239 static NTSTATUS
resolv_get_serverlist( void *args
)
241 const struct get_serverlist_params
*params
= args
;
242 DNS_ADDR_ARRAY
*addrs
= params
->addrs
;
243 DWORD needed
, found
, i
;
247 if (!_res
.nscount
) return DNS_ERROR_NO_DNS_SERVERS
;
248 if (!addrs
&& params
->family
!= WS_AF_INET
&& params
->family
!= WS_AF_INET6
)
250 *params
->len
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[_res
.nscount
]);
251 return ERROR_SUCCESS
;
254 for (i
= 0, found
= 0; i
< _res
.nscount
; i
++)
256 unsigned short sin_family
= AF_INET
;
257 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
258 if (_res
._u
._ext
.nsaddrs
[i
]) sin_family
= _res
._u
._ext
.nsaddrs
[i
]->sin6_family
;
260 if (filter( sin_family
, params
->family
)) continue;
263 if (!found
) return DNS_ERROR_NO_DNS_SERVERS
;
265 needed
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[found
]);
266 if (!addrs
|| *params
->len
< needed
)
268 *params
->len
= needed
;
269 return !addrs
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
271 *params
->len
= needed
;
272 memset( addrs
, 0, needed
);
273 addrs
->AddrCount
= addrs
->MaxCount
= found
;
275 for (i
= 0, found
= 0; i
< _res
.nscount
; i
++)
277 unsigned short sin_family
= AF_INET
;
278 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
279 if (_res
._u
._ext
.nsaddrs
[i
]) sin_family
= _res
._u
._ext
.nsaddrs
[i
]->sin6_family
;
281 if (filter( sin_family
, params
->family
)) continue;
283 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
284 if (sin_family
== AF_INET6
)
286 SOCKADDR_IN6
*sa
= (SOCKADDR_IN6
*)addrs
->AddrArray
[found
].MaxSa
;
287 sa
->sin6_family
= WS_AF_INET6
;
288 memcpy( &sa
->sin6_addr
, &_res
._u
._ext
.nsaddrs
[i
]->sin6_addr
, sizeof(sa
->sin6_addr
) );
289 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
294 SOCKADDR_IN
*sa
= (SOCKADDR_IN
*)addrs
->AddrArray
[found
].MaxSa
;
295 sa
->sin_family
= WS_AF_INET
;
296 sa
->sin_addr
.WS_s_addr
= _res
.nsaddr_list
[i
].sin_addr
.s_addr
;
297 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
302 return ERROR_SUCCESS
;
306 static NTSTATUS
resolv_set_serverlist( void *args
)
308 const IP4_ARRAY
*addrs
= args
;
313 if (!addrs
|| !addrs
->AddrCount
) return ERROR_SUCCESS
;
314 if (addrs
->AddrCount
> MAXNS
)
316 WARN( "too many servers: %d only using the first: %d\n",
317 (UINT
)addrs
->AddrCount
, MAXNS
);
318 _res
.nscount
= MAXNS
;
320 else _res
.nscount
= addrs
->AddrCount
;
322 for (i
= 0; i
< _res
.nscount
; i
++)
323 _res
.nsaddr_list
[i
].sin_addr
.s_addr
= addrs
->AddrArray
[i
];
325 return ERROR_SUCCESS
;
328 static NTSTATUS
resolv_query( void *args
)
330 const struct query_params
*params
= args
;
331 DNS_STATUS ret
= ERROR_SUCCESS
;
335 _res
.options
|= map_options( params
->options
);
337 if ((len
= res_query( params
->name
, ns_c_in
, params
->type
, params
->buf
, *params
->len
)) < 0)
338 ret
= map_h_errno( h_errno
);
344 const unixlib_entry_t __wine_unix_call_funcs
[] =
346 resolv_get_searchlist
,
347 resolv_get_serverlist
,
348 resolv_set_serverlist
,
356 static NTSTATUS
wow64_resolv_get_searchlist( void *args
)
362 } const *params32
= args
;
364 struct get_searchlist_params params
=
366 ULongToPtr(params32
->list
),
367 ULongToPtr(params32
->len
)
370 return resolv_get_searchlist( ¶ms
);
373 static NTSTATUS
wow64_resolv_get_serverlist( void *args
)
380 } const *params32
= args
;
382 struct get_serverlist_params params
=
385 ULongToPtr(params32
->addrs
),
386 ULongToPtr(params32
->len
)
389 return resolv_get_serverlist( ¶ms
);
392 static NTSTATUS
wow64_resolv_query( void *args
)
401 } const *params32
= args
;
403 struct query_params params
=
405 ULongToPtr(params32
->name
),
408 ULongToPtr(params32
->buf
),
409 ULongToPtr(params32
->len
)
412 return resolv_query( ¶ms
);
415 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
417 wow64_resolv_get_searchlist
,
418 wow64_resolv_get_serverlist
,
419 resolv_set_serverlist
,
425 #endif /* HAVE_RESOLV */