The tests are written in C++11, using the GoogleTest and GoogleMock
frameworks. They have their own independent autoconf setup, so that
users of the library need not have a C++ compiler just to get c-ares
working (however, the test/configure.ac file does assume the use of
a shared top-level m4/ directory). However, this autoconf setup has
only been tested on Linux and OSX so far.
Run with "./arestest", or "./arestest -v" to see extra debug info.
The GoogleTest options for running specific tests are also
available (e.g. "./arestest --gtest_filter=*Live*").
The tests are nowhere near complete yet (currently hitting around
60% coverage as reported by gcov), but they do include examples
of a few different styles of testing:
- There are live tests (ares-test-live.cc), which assume that the
current machine has a valid DNS setup and connection to the
internet; these tests issue queries for real domains but don't
particularly check what gets returned. The tests will fail on
an offline machine.
- There a few mock tests (ares-test-mock.cc) that set up a fake DNS
server and inject its port into the c-ares library configuration.
These tests allow specific response messages to be crafted and
injected, and so are likely to be used for many more tests in
future.
- To make this generation/injection easier, the dns-proto.h file
includes C++ helper classes for building DNS packets.
- Other library entrypoints that don't require network activity
(e.g. ares_parse_*_reply) are tested directly.
- There are few tests of library-internal functions that are not
normally visible to API users (in ares-test-internal.cc).
- A couple of the tests use a helper method of the test fixture to
inject memory allocation failures, using the earlier change to the
library to allow override of malloc/realloc/free.
- There is also an entrypoint to allow Clang's libfuzzer to drive
the packet parsing code in ares_parse_*_reply, together with a
standalone wrapper for it (./aresfuzz) to allow use of afl-fuzz
for further fuzz testing.
Pull in testing macros from the GNU autoconf archive to allow
configure scripts to test for and setup use of a C++11 compiler
(AX_CXX_COMPILE_STDCXX_11) and the pthreads library (AX_PTHREAD).
Note that these macros are not used by the main library autoconf,
just by the tests (which share the same m4/ directory).
Configure with:
./configure --enable-code-coverage
Show coverage output with:
make code-coverage-capture
Built on m4/ax_code_coverage.m4 from the GNU autoconf archive
to provide the macros to check for presence of gcov + lcov;
upstream macro modified to:
- Remove use of $(AM_DEFAULT_VERBOSITY) , as earlier versions of
autoconf (such as the one used by default on Travis) do not have this.
- Rather than automatically defining CODE_COVERAGE_RULES to be a set
of makefile rules that use ifeq/endif (which is GNU make-specific),
instead only define CODE_COVERAGE_RULES if coverages is turned on,
and in that case don't use conditionals in the makefile.
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
If an AF_UNSPEC query gets a valid response to its AAAA query,
but which has no IPv6 addresses in it, then the code chains on to
a A record query. However, the hostent from the AAAA response
was being leaked along the way (because it gets replaced before
the follow-on end_hquery() invocation).
If we get an allocation failure when processing a particular substring in a
TXT record, that failure is silently lost; fix that by propagating errors from
the inner loop to the outer loop.
When a server rejects an EDNS-equipped request, we retry without
the EDNS option. However, in TCP mode, the 2-byte length prefix was
being calculated wrong -- it was built from the answer length rather than
the length of the original request.
Also, it is theoretically possible that the call to realloc() might change
the data pointed to; to allow for this, qbuf also needs updating.
(Both these fixes were actually included in a patchset sent on the mailing
list in Oct 2012, but were included with other functional changes that
didn't get merged:
http://c-ares.haxx.se/mail/c-ares-archive-2012-10/0004.shtml)
The top two bits of the label length indicate whether this is a
label length (00) or an index to a name elsewhere in the message
(11). RFC1035 4.1.4 says that the other possible values for the
top two bits (01, 10) are reserved for future use.
CID 56884, pointed out by Coverity. We really should make this function
return an error code so that a malloc() failure can return back a major
failure.
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.