Some DNS servers don't properly ignore unknown EDNS options as the spec says they must, and instead will return EFORMERR.
See discussion roughly starting here: https://github.com/alpinelinux/docker-alpine/issues/366#issuecomment-2462530681
In this case the DNS server is known to support EDNS in general (as version prior to c-ares 1.33 worked which used EDNS), but when adding the EDNS DNS Cookie extension, they return EFORMERR. This is in violation of [RFC6891 6.1.2](https://datatracker.ietf.org/doc/html/rfc6891#section-6.1.2):
> Any OPTION-CODE values not understood by a responder or requestor MUST be ignored.
The server in this example actual echo's back the EDNS record further causing confusion that makes you think they might understand the record.
We need to catch an EFORMERR and re-attempt the query without EDNS completely since they are really non-compliant with EDNS. We may support additional EDNS extensions in the future and don't want to have to probe each individual extension with a braindead server.
Fixes#911
Authored-By: Brad House (@bradh352)
TSAN is warning about a thread concurrency issue that doesn't actually matter if the operation isn't atomic as its an optimization in this code path to skip timeout processing if we're shutting down due to ares_destroy().
Fix By: Jiwoo Park (@jimmy-park)
We added an optimization to stop retries on other address classes
on failures if one address class was received successfully. In
production, however, some odd misconfigured use cases could mean
an ipv6 address would be returned but the host was really only
capable of connecting to ipv4 machines.
We want to modify this optimization now to continue retries on
ipv4 even if ipv6 was received, but NOT the other way around.
It was always more likely that ipv6 resolution would cause the
delays due to system issues, as the world still really only
runs on ipv4...
Authored-By: Brad House (@bradh352)
Due to the way record duplication works, we might sometimes get a
misleading error code. Rewrite the error code to make better
sense.
Authored-By: Brad House (@bradh352)
When a release is tagged, automatically build the release package and
create a draft of the release. Since the build is automated we are also
performing provenance as per [SLSA3](https://slsa.dev/) and uploading
that as a release asset.
This also fixes a couple of recent issues:
* validation of the packaging itself was broken when we migrated from
cirrus ci to github actions.
* clang32 for msys2 has been deprecated causing building to fail.
Authored-By: Brad House (@bradh352)
As reported on Android 14, which recently added a fortify check for fcntl
F_SETFD to make sure only FD_CLOEXEC is ever passed:
dfe67d266c
We can't pass anything else to it. Even though on glibc, O_CLOEXEC
and FD_CLOEXEC are the same value, this isn't defined to be
portable in any way.
Fixes#900
Reported-By: Yuki San (@RealYukiSan)
Authored-By: Brad House (@bradh352)
this change addresses an issue with DNS cookie invalidation for users of
the legacy API and custom network stacks (e.g., Seastar's DNS).
in 02745437, we added an optional `agetsockname` to
`ares_socket_functions_ex` struct, and intended to skip calling this
function in DNS cookie invalidation if this function is not available
for legacy API users.
but we are still calling this system call directly, this fails Seastar's
DNS which uses c-ares to resolve names, and it uses the socket function
table to override the network stack to use its own userspace TCP/IP
stack, in that case, the fd passed to c-ares is not a valid file
descriptor, hence the call fails.
in this change, we
- replace direct getsockname() call with sock_funcs.agetsockname()
- skip the call if agetsockname() is not configured
Refs 02745437
Signed-off-by: Kefu Chai (@tchaikov)
Some external users swap out the entire IP stack, such as
[Seastar](https://github.com/scylladb/seastar) that uses DPDK. So we
need to allow them to override all network stack functions used by
c-ares. Since we don't know what network functions may be needed in the
future, we need to make a versioned structure that can be expanded.
We'll need to disable any features in the future if the versioned
interface is less than is required to support any new features.
We recently had a regression when we added DNS Cookie support as we
relied on `getsockname()` to get the local source ip address, but we
were calling the native version since there was no registered callback
available. We will mark this as optional and just skip this step in DNS
Cookie invalidation if its not available for the legacy api users.
Supersedes #893
Authored-By: Brad House (@bradh352)
Invalid arguments might be silently ignored if they were determined
they might be valid hostnames. Also it was common for people to
specify `-s server` in old c-ares versions out of habbit, lets
re-add that functionality since it doesn't conflict with bind dig
options.
Authored-By: Brad House (@bradh352)
When got a truncated UDP packet and switch the query to TCP, use the
same port.
Fallback TCP port was always default 53.
Tested on e037002. Also existed before a41b85e.
To reproduce it, on Windows:
1. Build and launch a "parrot" DNS server, which just echo back the
query with `data[3] |= 0x82`, meaning with flag truncated is true. For
example on: `127.0.0.2:33053`.
2. Launch another DNS server, on `127.0.0.2:53`. Or use a packet capture
tool, like Wireshark.
3. Run `adig @127.0.0.2 -p 33053 google.com`. You will see the log
appears on TCP port 53.
Using a non-default port DNS server, `adig @127.0.0.2 -p 33053 -t txt
gitlab.com` is very likely to trigger it, as the answer would be very
long (rcvd: 1465).
Authored-By: @lifenjoiner
The c-ares dig utility outputs a similar format to the bind dig utility,
we should also make it take arguments that mimic theirs for
compatibility.
This PR starts down that path supporting some of the major options.
Fixes#885
Authored-By: Brad House (@bradh352)
If you bind to a local address, you now only have approx 32k possible
source ports to initiate connections.
In modern days that can quickly run out.
setting IP_BIND_ADDRESS_NO_PORT let's the kernel choose a port at
connect time, increasing the limit of combinations to around a million.
Authored-By: Cristian Rodríguez (@crrodriguez)
Some of the new library functions didn't have any specific test cases
or were very limited. Lets add a few more to improve code coverage.
There's still a lot to go, but this is a good start.
Authored-By: Brad House (@bradh352)
As per Issue #883, an incorrect `libcares.pc` can be generated when
`CMAKE_THREAD_LIBS_INIT` contains a value like `-lpthread` because it
gets added to `libcares.pc` with another `-l` prefix. We can't control
the behavior of `CMAKE_THREAD_LIBS_INIT` since its set by `FIND_PACKAGE
(Threads)`.
Lets strip the `-l` prefix from the library before adding it to
`CARES_DEPENDENT_LIBS` which is used in the generation of `libcares.pc`.
Fixes#883
Reported-By: 前进,前进,进 (@leleliu008)
Fix By: Brad House (@bradh352)
The DNS server format is insufficient for future configurations, such as
supporting DNS over TLS (DoT) and DNS over HTTPS (DoH), as well as
additional functionality such as domain-specific servers. Already, in
the case where different UDP and TCP ports are used, it is impossible to
represent in the current format.
In order to try to use some standardized format, we are going to define
our own URI schemes that should be parse-able by any URI parser. The new
scheme will only be used when the configuration cannot otherwise be
expressed using the current `ipaddr%iface:port` format, which is the
format used as the nameserver configuration in `/etc/resolv.conf`.
However, the parser `ares_set_servers_csv()` shall accept the new URI
scheme format even when it is not necessary.
This PR implements a URI parser and writer and hooks the basic usage
into `ares_set_servers_csv()` and `ares_get_servers_csv()` as well as
provides updated documentation in the relevant manpages.
We will define these URI schemes:
* `dns://` - Normal DNS server (UDP + TCP). We need to be careful not to
conflict with query params defined in
https://datatracker.ietf.org/doc/html/rfc4501 since we'd technically be
extending this URI scheme. Port defaults to `53`.
* `dns+tls://` - DNS over TLS. Port defaults to `853`.
* `dns+https://` - DNS over HTTPS. Port defaults to `443`.
We initially will define these query parameters (additional arguments
may be required in the future to specify options such as TLS certificate
validation rules):
* `tcpport` - TCP port to use, only for `dns://` scheme. The `port`
specified as part of the `authority` component of the URI will be used
for both UDP and TCP by default, this option will override the TCP port.
* `ipaddr` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains a hostname, this is used to
specify the ip address of the hostname. If not specified, will need to
use a non-secure server to perform a DNS lookup to retrieve this
information. It is always recommended to have both the ip address and
fully qualified domain name specified.
* `hostname` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains an ip address, this is used to
specify the fully qualified domain name of the server. If not specified,
will need to use a non-secure server to perform a DNS reverse lookup to
retrieve this information. It is always recommended to have both the ip
address and fully qualified domain name specified.
* `domain` - If specified, this server is a domain-specific server. Any
queries for this domain will be routed to this server. Multiple servers
may be tagged with the same domain.
Examples:
```
dns://8.8.8.8
dns://[2001:4860:4860::8888]
dns://[fe80::b542:84df:1719:65e3%en0]
dns://192.168.1.1:55
dns://192.168.1.1?tcpport=1153
dns://10.0.1.1?domain=myvpn.com
dns+tls://8.8.8.8?hostname=dns.google
dns+tls://one.one.one.one?ipaddr=1.1.1.1
```
NOTE: While we are defining the scheme for things like domain-specific
servers, DNS over TLS and DNS over HTTPS, the underlying implementations
for those features do not yet exist and therefore will result in errors
if they are attempted to be used.
### Non-compliance in implementation
All these could be easily implemented/fixed if desired, however any such
changes would be of no use to the current c-ares usage of URIs:
* Does not currently support relative references
* Requires use of the authority section, blank is not allowed
* The query string is interpreted to be in
[application/x-www-form-urlencoded](https://en.wikipedia.org/wiki/Application/x-www-form-urlencoded)
format only and will result in parse errors if it is not. This is the
most common format used, however technically not valid to mandate this
format is used. We could add flags in the future to treat the query
string as opaque and leave it to the user to process. Or we could
internally have a list of schemes that use this format.
* [IDNA](https://en.wikipedia.org/wiki/Internationalized_domain_name) is
not supported.
* Does not support hex-encoded IPv4 addresses (this is compliant with RFC3986, but not WHATWG)
Authored-By: Brad House (@bradh352)
The solaris images have been updated to be a bit more modernized. Switch
to using the new image and enable the use of running tests through GDB
to be able to print backtraces in case of failures.
Authored-By: Brad House (@bradh352)
ares_platform.c contains some legacy code to support things like Windows
9x and Windows CE 6, those have long since been discontinued.
Lets kill these legacy files to clean up some cruft.
Signed-off-by: Brad House (@bradh352)