When `ares_cancel()` was invoked, `ares_gethostbyaddr()`
queries would fail with `ENOTFOUND` instead of `ECANCELLED`.
It seems appropriate to treat `ares_cancel()` like `ares_destroy()`,
but I would appreciate review of the correctness of this change.
Ref: https://github.com/nodejs/node/issues/14814Closes#138
The TESTS target runs fuzzcheck.sh so make sure it is included
in the distributed tarball.
(The test itself will be pointless when run on a distribution, because
the fuzzing corpus directories are not shipped, but at least this
means that `make -C test test` should work.)
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.
The added api requires both some typedefs not previously imported
into the test build + the test code did not fully deal with
socket differences on windows.
* Added test case macro to automatically run tests twice, once "normal",
once with virtual IO.
* Changed most "live" query tests to run in dual mode to verify
at least simple socket IO via virtual functions
* Added test case for settings/duping socket functions & callback data
Built tarballs are not including all of the files needed
to build the test suite because they are missing from the
<target>_SOURCES variable in Makefile.am.
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.
GoogleTest assumes that there is a null pointer in argv[argc],
so make it look like that. Without this change, tests run with
command-line arguments get memory errors under valgrind/ASAN.
When fuzzing with AFL, if the LLVM-based instrumentation is
used (via the afl-clang-fast wrapper), then it is possible to
have a single execution of the fuzzer program iterate multiple
times over the fuzzing entrypoint (similar to libFuzzer's normal
mode of execution) with different data. This is much (e.g. 10x)
faster.
Add code to support this, by checking whether __AFL_LOOP is
defined at compile-time.
Also, shift the code to effectively be C rather than C++.
No need to depend on the rest of the test code (ares-test.h) for
the fuzzer entrypoint; this makes the entrypoint slightly simpler
to build with LLVM's libFuzzer.
Also shift the code to effectively be C rather than C++
Add a test script that runs the fuzzing command over the
corpus of DNS packets. This doesn't actually do any fuzzing
(it just runs them as inputs without generating any variations)
but it does ensure that the fuzzing entrypoint is still working.
For fuzz testing it is useful to start from a corpus of valid
packets, so fill out the test/fuzzinput/ directory with a bunch
of inputs.
These packets were generated by temporarily modifying the c-ares
process_answer() function to save off any incoming response messages.
For UDP tests, there's a chance of a retry. EXPECT_CALL only
expects a single request to arrive at the server; ON_CALL allows
for a UDP retry and repeats the same answer.
Note that ON_CALL and EXPECT_CALL can't be mixed in the same
test, and that tests that have a varied sequence of responses
for the same repeated request still have to use EXPECT_CALL.