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)