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 WCHAR
*list
= params
->list
;
134 for (i
= 0; i
< MAXDNSRCH
+ 1 && _res
.dnsrch
[i
]; i
++)
135 needed
+= (strlen(_res
.dnsrch
[i
]) + 1) * sizeof(WCHAR
);
136 needed
+= sizeof(WCHAR
); /* null terminator */
138 if (!list
|| *params
->len
< needed
)
140 *params
->len
= needed
;
141 return !list
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
144 *params
->len
= needed
;
147 end
= ptr
+ needed
/ sizeof(WCHAR
);
148 for (i
= 0; i
< MAXDNSRCH
+ 1 && _res
.dnsrch
[i
]; i
++)
149 ptr
+= ntdll_umbstowcs( _res
.dnsrch
[i
], strlen(_res
.dnsrch
[i
]) + 1, ptr
, end
- ptr
);
150 *ptr
= 0; /* null terminator */
151 return ERROR_SUCCESS
;
155 static inline int filter( unsigned short sin_family
, USHORT family
)
157 if (sin_family
!= AF_INET
&& sin_family
!= AF_INET6
) return TRUE
;
158 if (sin_family
== AF_INET6
&& family
== WS_AF_INET
) return TRUE
;
159 if (sin_family
== AF_INET
&& family
== WS_AF_INET6
) return TRUE
;
164 #ifdef HAVE_RES_GETSERVERS
166 static NTSTATUS
resolv_get_serverlist( void *args
)
168 const struct get_serverlist_params
*params
= args
;
169 DNS_ADDR_ARRAY
*addrs
= params
->addrs
;
170 struct __res_state
*state
= &_res
;
171 DWORD i
, found
, total
, needed
;
172 union res_sockaddr_union
*buf
;
176 total
= res_getservers( state
, NULL
, 0 );
177 if (!total
) return DNS_ERROR_NO_DNS_SERVERS
;
179 if (!addrs
&& params
->family
!= WS_AF_INET
&& params
->family
!= WS_AF_INET6
)
181 *params
->len
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[total
]);
182 return ERROR_SUCCESS
;
185 buf
= malloc( total
* sizeof(union res_sockaddr_union
) );
186 if (!buf
) return ERROR_NOT_ENOUGH_MEMORY
;
188 total
= res_getservers( state
, buf
, total
);
190 for (i
= 0, found
= 0; i
< total
; i
++)
192 if (filter( buf
[i
].sin
.sin_family
, params
->family
)) continue;
195 if (!found
) return DNS_ERROR_NO_DNS_SERVERS
;
197 needed
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[found
]);
198 if (!addrs
|| *params
->len
< needed
)
200 *params
->len
= needed
;
201 return !addrs
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
203 *params
->len
= needed
;
204 memset( addrs
, 0, needed
);
205 addrs
->AddrCount
= addrs
->MaxCount
= found
;
207 for (i
= 0, found
= 0; i
< total
; i
++)
209 if (filter( buf
[i
].sin
.sin_family
, params
->family
)) continue;
211 if (buf
[i
].sin6
.sin6_family
== AF_INET6
)
213 SOCKADDR_IN6
*sa
= (SOCKADDR_IN6
*)addrs
->AddrArray
[found
].MaxSa
;
214 sa
->sin6_family
= WS_AF_INET6
;
215 memcpy( &sa
->sin6_addr
, &buf
[i
].sin6
.sin6_addr
, sizeof(sa
->sin6_addr
) );
216 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
220 SOCKADDR_IN
*sa
= (SOCKADDR_IN
*)addrs
->AddrArray
[found
].MaxSa
;
221 sa
->sin_family
= WS_AF_INET
;
222 sa
->sin_addr
.WS_s_addr
= buf
[i
].sin
.sin_addr
.s_addr
;
223 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
229 return ERROR_SUCCESS
;
234 static NTSTATUS
resolv_get_serverlist( void *args
)
236 const struct get_serverlist_params
*params
= args
;
237 DNS_ADDR_ARRAY
*addrs
= params
->addrs
;
238 DWORD needed
, found
, i
;
242 if (!_res
.nscount
) return DNS_ERROR_NO_DNS_SERVERS
;
243 if (!addrs
&& params
->family
!= WS_AF_INET
&& params
->family
!= WS_AF_INET6
)
245 *params
->len
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[_res
.nscount
]);
246 return ERROR_SUCCESS
;
249 for (i
= 0, found
= 0; i
< _res
.nscount
; i
++)
251 unsigned short sin_family
= AF_INET
;
252 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
253 if (_res
._u
._ext
.nsaddrs
[i
]) sin_family
= _res
._u
._ext
.nsaddrs
[i
]->sin6_family
;
255 if (filter( sin_family
, params
->family
)) continue;
258 if (!found
) return DNS_ERROR_NO_DNS_SERVERS
;
260 needed
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[found
]);
261 if (!addrs
|| *params
->len
< needed
)
263 *params
->len
= needed
;
264 return !addrs
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
266 *params
->len
= needed
;
267 memset( addrs
, 0, needed
);
268 addrs
->AddrCount
= addrs
->MaxCount
= found
;
270 for (i
= 0, found
= 0; i
< _res
.nscount
; i
++)
272 unsigned short sin_family
= AF_INET
;
273 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
274 if (_res
._u
._ext
.nsaddrs
[i
]) sin_family
= _res
._u
._ext
.nsaddrs
[i
]->sin6_family
;
276 if (filter( sin_family
, params
->family
)) continue;
278 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
279 if (sin_family
== AF_INET6
)
281 SOCKADDR_IN6
*sa
= (SOCKADDR_IN6
*)addrs
->AddrArray
[found
].MaxSa
;
282 sa
->sin6_family
= WS_AF_INET6
;
283 memcpy( &sa
->sin6_addr
, &_res
._u
._ext
.nsaddrs
[i
]->sin6_addr
, sizeof(sa
->sin6_addr
) );
284 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
289 SOCKADDR_IN
*sa
= (SOCKADDR_IN
*)addrs
->AddrArray
[found
].MaxSa
;
290 sa
->sin_family
= WS_AF_INET
;
291 sa
->sin_addr
.WS_s_addr
= _res
.nsaddr_list
[i
].sin_addr
.s_addr
;
292 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
297 return ERROR_SUCCESS
;
301 static NTSTATUS
resolv_set_serverlist( void *args
)
303 const IP4_ARRAY
*addrs
= args
;
308 if (!addrs
|| !addrs
->AddrCount
) return ERROR_SUCCESS
;
309 if (addrs
->AddrCount
> MAXNS
)
311 WARN( "too many servers: %d only using the first: %d\n",
312 (UINT
)addrs
->AddrCount
, MAXNS
);
313 _res
.nscount
= MAXNS
;
315 else _res
.nscount
= addrs
->AddrCount
;
317 for (i
= 0; i
< _res
.nscount
; i
++)
318 _res
.nsaddr_list
[i
].sin_addr
.s_addr
= addrs
->AddrArray
[i
];
320 return ERROR_SUCCESS
;
323 static NTSTATUS
resolv_query( void *args
)
325 const struct query_params
*params
= args
;
326 DNS_STATUS ret
= ERROR_SUCCESS
;
330 _res
.options
|= map_options( params
->options
);
332 if ((len
= res_query( params
->name
, ns_c_in
, params
->type
, params
->buf
, *params
->len
)) < 0)
333 ret
= map_h_errno( h_errno
);
339 const unixlib_entry_t __wine_unix_call_funcs
[] =
341 resolv_get_searchlist
,
342 resolv_get_serverlist
,
343 resolv_set_serverlist
,
351 static NTSTATUS
wow64_resolv_get_searchlist( void *args
)
357 } const *params32
= args
;
359 struct get_searchlist_params params
=
361 ULongToPtr(params32
->list
),
362 ULongToPtr(params32
->len
)
365 return resolv_get_searchlist( ¶ms
);
368 static NTSTATUS
wow64_resolv_get_serverlist( void *args
)
375 } const *params32
= args
;
377 struct get_serverlist_params params
=
380 ULongToPtr(params32
->addrs
),
381 ULongToPtr(params32
->len
)
384 return resolv_get_serverlist( ¶ms
);
387 static NTSTATUS
wow64_resolv_query( void *args
)
396 } const *params32
= args
;
398 struct query_params params
=
400 ULongToPtr(params32
->name
),
403 ULongToPtr(params32
->buf
),
404 ULongToPtr(params32
->len
)
407 return resolv_query( ¶ms
);
410 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
412 wow64_resolv_get_searchlist
,
413 wow64_resolv_get_serverlist
,
414 resolv_set_serverlist
,
420 #endif /* HAVE_RESOLV */