qsort is not stable, in order to make it stable we need to record
the original index and add it as a secondary sort value when the
metrics are equal to prevent using DNS servers that may not work
at all as reported by some users.
This change solves issue #53.
Support for suffix search lists was already built in for Linux. The search list could be set via set_search. With this change the suffix search list from Windows is read from the registry and then set into the ares configuration via set_search. There are two sources for the search list:
The global DNS suffix search list.
The primary and connection specific DNS suffixes if the global is not available.
Contributed by @ChristianAmmer
Socklen_t should not be used in code, instead ares_socklen_t should be used.
Convert ssize_t to ares_ssize_t for portability since the public API now exposes this.
Original Patch From Brad Spencer:
https://c-ares.haxx.se/mail/c-ares-archive-2016-04/0000.shtml
My modifications include:
* Dynamically find GetBestRoute2 since it is a Windows Vista+ symbol, and will fall back to prior behavior when not available.
* Prefer get_DNS_AdaptersAddresses as the modifications should alleviate the concerns which caused us to prefer get_DNS_NetworkParams
* Update AppVeyor to use MinGW-w64 instead of the legacy MinGW
* Fix compile error in test suite for Windows.
Original message from patch below:
From: Brad Spencer <bspencer@blackberry.com>
Date: Fri, 29 Apr 2016 14:26:23 -0300
On Windows, the c-ares DNS resolver tries first to get a full list of
DNS server addresses by enumerating the system's IPv4/v6 interfaces and
then getting the per-interface DNS server lists from those interfaces
and joining them together. The OS, at least in the way the c-ares
prefers to query them (which also may be the only or best way in some
environments), does not provide a unified list of DNS servers ordered
according to "current network conditions". Currently, c-ares will then
try to use them in whatever order the nested enumeration produces, which
may result in DNS requests being sent to servers on one interface
(hosting the current default route, for example) that are only intended
to be used via another interface (intended to be used when the first
interface is not available, for example). This, in turn, can lead to
spurious failures and timeouts simply because of the server address
order that resulted because of the enumeration process.
This patch makes the (safe?) assumption that there is no other better
rule to chose which interface's DNS server list should be prioritized.
After all, a DNS lookup isn't something "per network"; applications
don't look up "these DNS names on this interface and those DNS names on
that interface". There is a single resource pool of DNS servers and the
application should presume that any server will give it the "right"
answer. However, even if all DNS servers are assumed to give equally
useful responses, it is reasonable to expect that some DNS servers will
not accept requests on all interfaces. This patch avoids the problem by
sorting the DNS server addresses using the Windows IPv4/v6 routing tables.
For example, a request to DNS server C on interface 2 that is actually
sent over interface 1 (which may happen to have the default route) may
be rejected by or not delivered to DNS server C. So, better to use DNS
servers A and B associated with interface 1, at least as a first try.
By using the metric of the route to the DNS server itself as a proxy for
priority of the DNS server in the list, this patch is able to adapt
dynamically to changes in the interface list, the DNS server lists per
interface, which interfaces are active, the routing table, and so on,
while always picking a good "best" DNS server first.
In cases where any DNS server on any interface will do, this patch still
seems useful because it will prioritize a lower-metric route's (and thus
interface's) servers.
Fix up a couple of problems with configuring whether c-ares rotates
between different name servers between requests.
Firstly, ares_save_options() returns (in *optmask) the value of
(channel->optmask & ARES_OPT_ROTATE), which doesn't necessarily
indicate whether the channel is or is not actually doing rotation.
This can be confusing/incorrect if:
- the channel was originally configured without ARES_OPT_ROTATE
(so it appears that the channel is not rotating)
- the /etc/resolv.conf file includes the 'rotate' option
(so the channel is actually performing rotation).
Secondly, it is not possible to reliably configure a channel
to not-rotate; leaving off ARES_OPT_ROTATE is not enough, since
a 'rotate' option in /etc/resolv.conf will turn it on again.
Therefore:
- add an ARES_OPT_NOROTATE optmask value to allow explicit
configuration of no-rotate behaviour
- in ares_save_options(), report the value of channel->rotate
as exactly one of (optmask & ARES_OPT_ROTATE) or
(optmask & ARES_OPT_NOROTATE).
In terms of back-compatibility:
- existing apps that set ARES_OPT_ROTATE will continue to rotate,
and to have ARES_OPT_ROTATE reported back from ares_save_options()
- existing apps that don't set ARES_OPT_ROTATE will continue to
use local config/defaults to decide whether to rotate, and will
now get ARES_OPT_ROTATE or ARES_OPT_NOROTATE reported back from
ares_save_options() rather than 0.
Commit 46bb820be3 ("ares_init_options: don't lose init failure")
changed init behaviour so that earlier errors in initialization
weren't lost. In particular, if the user passes in specific
options but they are not applied (e.g. because of an allocation
failure), that failure needs to be reported back to the user; this
also applies when duplicating a channel with ares_dup().
However, other initialization failures can be ignored and
overridden -- in particular, if init_by_resolv_conf() or
init_by_environment() fail, then falling back to default values
is OK.
So only preserve failures from the init_by_options() stage, not
from all initialization stages.
Fixes issue 60.
Modern Linux systems may have libnss_resolve from systemd as the
resolver, which is then configured in /etc/nsswitch.conf with
the "resolve" keyword rather than "dns".
Fixes#33
After 46bb820be3 `init_by_resolv_conf`
errors are no longer swallowed in `ares_init_options`. This has exposed
a previously unknown bug in `lookups` initialization code.
If there is no lookup configuration in `resolv.conf`,
`init_by_resolv_conf` will attempt to read it from other files available
on the system. However, some of these files may have restricted
permissions (like `600`), which will lead to `EACCESS` errno, which in
turn is handled like a fatal error by `init_by_resolv_conf`.
However, it sounds illogical that this error should be handled as a
fatal. There is a `init_by_defaults` call that overrides `lookups` with
default value, and certainly possible absence of lookup information is
the reason why this function exists in a first place!
I suggest handling any `fopen` errors as non-fatal ones, allowing to
pick up the `lookups` value from different config files, or to pick up
default value.
This function sets a callback that is invoked after the socket is
created, but before the connection is established. This is an ideal
time to customize various socket options.
Add user-visible entrypoints ares_{get,set}_servers_ports(3), which
take struct ares_addr_port_node rather than struct ares_addr_node.
This structure includes a UDP and TCP port number; if this is set
to zero, the channel-wide port values are used as before.
Similarly, add a new ares_set_servers_ports_csv(3) entrypoint, which
is analogous to ares_set_servers(3) except it doesn't ignore any
specified port information; instead, any per-server specified port
is used as both the UDP and TCP port for that server.
The internal struct ares_addr is extended to hold the UDP/TCP ports,
stored in network order, with the convention that a value of zero
indicates that the channel-wide UDP/TCP port should be used.
For the internal implementation of ares_dup(3), shift to use the
_ports() version of the get/set functions, so port information is
transferred correctly to the new channel.
Update manpages, and add missing ares_set_servers_csv to the lists
while we're at it
Allow explicit configuration of the channel's sortlist, by
specifying a string in the same format as the equivalent
/etc/resolv.conf option.
This allows library users to perform the same configuration
that is available via /etc/resolv.conf, but without needing
to change that file.
Add a new ares_library_init_mem() initialization function for the
library which allows the library user to specify their own malloc,
realloc & free equivalents for use library-wide.
Store these function pointers in library-wide global variables,
defaulting to libc's malloc(), realloc() and free().
Change all calls to malloc, realloc and free to use the function pointer
instead. Also ensure that ares_strdup() is always available
(even if the local environment includes strdup(3)), and change the
library code to always use it.
Convert calls to calloc() to use ares_malloc() + memset
Add comments for the benefit of the lcov tool, marking
lines that cannot be hit. Typically these are fall-back
protection arms that are already covered by earlier checks,
and so it's not worth taking out the unhittable code (in case
someone changes the code between the two places in future).
If we get an allocation failure on 2nd or later entry in the sortlist, the
code would return ENOMEM but still leave the initial entries allocated.
Ensure that *sortlist is set to NULL whenever ENOMEM is returned.
If the attempt to transfer IPv6 servers from the old to the new channel
fails, the previous code would still return a channel to the user even though
an error return code was generated. This makes it likely that users would
leak the channel, so explicitly clear the channel in this case.
If (say) init_by_options() fails, the subsequent call to
init_by_defaults() was overwriting the return code with
success. Still call init_by_defaults() regardless, but track
its return value separately
Update for commit affc63cba8.
The original patch from Gregor Jasny did not have the break
statement; I incorrectly added it to prevent continuing the loop.
However, the later entries in the array would then be left
uninitialized, causing problems for later cleanup.
So fix to match Gregor's original patch, with apologies.
On iPhone targets like iOS, watchOS or tvOS the file
/etc/resolv.conf cannot be used to configure cares.
Instead the resolver library is queried for configuration
values.
CC: Yury Kirpichev <ykirpichev@yandex-team.ru>
This patch is fixing the dns lookup issue due to dummy dns information
of a disconnected adapter(in my case is a bluetooth adapter). I changed
the dns lookup policy to try GetNetworkParams first because the
GetNetworkParams provides the most reliable dns information (lots of
checks were done by system). I also filter out inoperable adapter in
DNS_AdaptersAddresses in case GetNetworkParams fail.
It's possible that, if ares_save_options failed, the opts structure
would contain some allocated memory. Calling ares_destroy_options in
this case is safe, because ares_save_options zeroes out the memory
initially.
When attempting to build a search domain from the local hostname
(used as a fallback when no other methods have given a search
domain), the code doubles the buffer size on each loop iteration.
However, the loop previously had a WHILE_FALSE terminator so the continue
statement exited the loop rather than going round again.
Make sure that the symbols are always exported and present in c-ares.
Make the headers prefixed with 'ares'.
Removed the inet_ntop.h version as it no longer features any content.
The UDP and TCP port are stored in network byte order in the
ares_channeldata, but are passed in to ares_init_options() in host byte
order. Thus we must return them from ares_save_options() in host byte
order too, or a duplicated channel will convert them again, leading to a
nonfunctional channel and a mysterious connection refused error from
ares_gethostbyname(). This breaks ares_dup(), thus the curl easy API
when c-ares is used by curl, and thus all the curl easy API's users.
Before, c-ares always used the first DNS server on Android, causing
network problems if this DNS server was not available.
Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
I experienced a buffer overrun exception in c-ares on Windows and
tracked it down to be an error in the calculation of the 'left' variable
in get_iphlpapi_dns_info().
I changed the variable type of 'left' to a _signed_ type because of the
subtraction arithmetic; not sure if a long is the best choice