djbdns-client 5 file formats djbwares
djbdns-client configuring the DNS client in djbdns

## Description

The DNS client library common to all djbwares utilities is centred upon a `dns_resolve()` function. Like other DNS client libraries, it talks to one or more (local) proxy DNS servers, which do most of the actual lookup work. Several domain names are handled by the library internally, however, without contacting any servers at all.

There are separate DNS server configuration settings for:

- DNS-SD lookups under `service.arpa.`, per RFC 9665;

- `onion.` lookups, per RFC 7686;

- mDNS lookups under `local.` and several subdomains of `ip-addr.arpa.` and `ip6.arpa.` corresponding to link-local IP addresses, per RFC 8375;

- homenet lookups under `home.arpa.`, per RFC 8375; and

- regular lookups, for everything else.

There is also a name qualification procedure that some tools apply to some input names before performing the name lookups proper.

Generally, debugging tools do not apply qualification to the domain names that they are given to perform lookups on, but non-debugging utilities apply name qualification.

### Short circuits and internally synthesized answers

If the input string to be passed through name qualification is the human-readable form of an IP address, the DNS client simply synthesizes and returns corresponding `A` and `AAAA` resource records (and empty resource record sets for other types) without performing any name qualification or lookups. This is designed to accommodate a common mis-usage where people supply human-readable form IP addresses where domain names should be supplied. Renormalization is performed, so leading zeroes are discarded; but numeric values that are not legal for an IP address mean that the string will not take this short circuit synthesis route.

dnscache 1 also filters queries for such errors, but the DNS client library tries not to send such queries in the first place.
IP version 6 addresses are currently not recognized in abbreviated form. `::1` is not taken to be a human-readable form of an IP version 6 address, for example. It must be spelled out in full as the single-label pseudo domain name `0:0:0:0:0:0:0:1`.

#### Historic mis-behaviour

In the original Bernstein DNS client library, if the input string was to be passed through name qualification, and was an arbitrary length string of arbitrary valued dot-separated numbers it would be converted, without any name qualification or lookups being performed, into possibly more than 1 IPv4 address, not caring about numeric overflow or values larger than 256, and not caring about partially-complete addresses. This wholly undocumented mechanism would lead to stupid consequences and real-world risks such as:

- the domain name `6.2.8.2.999999999999` apparently existing and having an IPv4 address,

- the domain name `24.75.345.200` (from a Sandra Bullock movie in the 1990s) apparently existing and having someone's real (and not reserved-use) IPv4 address, and

- the domain name `1729.86400.99999.2147483647.100000000.10000000.10000000.10000000` apparently existing and having two IPv4 addresses.

This undocumented behaviour, that for one thing would make the deliberately invalid or malformed IPv4 addresses used in movies and television dramas work and have surprising consequences for unsuspecting people who just happened to be assigned the real IP addresses, is not present in this version of the DNS client library.

#### After name qualification

When name qualification is used, various queries have directly synthesized answers created by the DNS client library itself, short-circuiting any query to a proxy DNS server.

Per RFC 7686, if there are no configured `onion.` proxy DNS servers, `onion.` and all of its subdomains are synthetic "no such domain" errors. Per RFC 6761, `invalid.` and all of its subdomains are synthetic "no such domain" errors.

Per the implication of RFC 6761 and long-standing `/etc/hosts` convention, reverse lookups of 127.a.b.c IPv4 addresses map to `c.b.a.127.localhost.`, except that 127.0.0.1 maps to `localhost.`. Likewise, reverse lookups of the ::1 IPv6 address map to `localhost.`. In the forward direction, A and AAAA lookups of `localhost.` map to 127.0.0.1 and ::1 respectively, and A and AAAA lookups of `c.b.a.127.localhost.` map to 127.a.b.c and ::FFFF:127.a.b.c respectively.

Per RFC 8880, `ipv4only.arpa.` exists synthetically with the fixed IPv4 addresses 192.0.0.170 and 192.0.0.171, reverse lookups of those IPv4 addresses synthetically map back to it, and all of its subdomains are synthetic "no such domain" errors. NAT64 prefix discovery is supposed not to be using this DNS client library.

dnscache 1 and walldns 1 also synthesize data for some of these domain names. But what answers a proxy DNS server can synthesize are different to what answers a content DNS server can synthesize and different to what answers a DNS client library can synthesize. Many "special-use domain names" have different rules for all three.

## Location of the proxy DNS servers

The IP addresses of the one or more proxy DNS servers are determined as follows:

1. The primary configuration setting is the process environment of whatever tool is running. The values of two environment variables are taken to be a list of whitespace-separated IP addresses and a numeric port number:

   `DNSCACHEIP_DNSSD` and `DNSCACHEPORT_DNSSD`

     the proxy DNS server(s) used for DNS Service Discovery

   `DNSCACHEIP_HOME` and `DNSCACHEPORT_HOME`

     the proxy DNS server(s) used for homenet

   `DNSCACHEIP_ONION` and `DNSCACHEPORT_ONION`

     the proxy DNS server(s) used for `onion.`

   `DNSCACHEIP_MDNS` and `DNSCACHEPORT_MDNS`

     the proxy DNS server(s) used for multicast DNS

   `DNSCACHEIP` and `DNSCACHEPORT`

     the regular proxy DNS server(s) used for everything else

2. If this environment variable is not found, the library falls back to resolv.conf 5. The values of various directives are likewise taken to be a list of whitespace-separated IP addresses.

   `nameserver-dnssd`

     the proxy DNS server(s) used for DNS Service Discovery

   `nameserver-home`

     the proxy DNS server(s) used for homenet

   `nameserver-onion`

     the proxy DNS server(s) used for `onion.`

   `nameserver-mdns`

     the proxy DNS server(s) used for multicast DNS

   `nameserver`

     the regular proxy DNS server(s) used for everything else

   All other configuration settings in resolv.conf 5 are ignored. This is a compatibility configuration mechanism only.
   Several of these are extensions to the conventional resolv.conf 5 as used by ISC's BIND DNS client library.

3. If no other configuration is specified, the library falls back to hardwired default IP address of 127.0.0.1 and ::1 for everything except for mDNS for which the hardwired defaults are 224.0.0.251 and FF02::FB. This is the same fallback as other DNS client libraries, and running an instance of dnscache 1 listening on either 127.0.0.1 or ::1 is a conventional system configuration.

## Name qualification

Several tools pass input strings through a name qualification phase before performing lookups with the `dns_resolve()` function. The name qualification procedure is the simple iterative application of a set of string matching and replacement rules.

### Construction of the ruleset

The ruleset is determined as follows:

1. The primary configuration setting is the process environment of whatever tool is running. The value of the `DNSREWRITEFILE` environment variable is taken to be the name of a file from which rewrite rules are read.

2. If this environment variable is not found, the library falls back to `/etc/dnsrewrite` as the name of the file.

3. If the rules file is not found, the library falls back to the `LOCALDOMAIN` environment variable. If it exists, its value is used to synthesize rules. Its value is treated as a whitespace-separated list of domains and is turned into a `?:.domain+.domain` rewrite rule with the domains separated by `+`. A final `*.:` rule is appended.

4. If neither the rules file nor the `LOCALDOMAIN` environment variable are found, the library falls back to resolv.conf 5 and synthesizes rules from its directives. The first `search` or a `domain` directive followed by a whitespace-separated list of domains is turned into a `?:.domain+.domain` rewrite rule with the domains separated by `+`. A final `*.:` rule is appended.

   All other configuration settings in resolv.conf 5 are ignored. This is a compatibility configuration mechanism only.

5. If not even a suitable directive in resolv.conf 5 is found, the library falls back on the result of the operating system's gethostname 2 library function. A `?:.domain` rewrite rule is synthesized where domain is the part of the (dynamic) hostname that follows the first dot. A final `*.:` rule is appended.

### Syntax of rewrite rules

Rules comprise a single leading character, then a match, a `:`, and a replacement.

`=match:replacement`

  An exact match rule and complete replacement rule. If the input string exactly matches match then the replacement is substituted.

`-match:replacement`

  A suffix match and complete replacement rule. If a suffix of the input string exactly matches match then the replacement is substituted.

`*match:replacement`

  An unconstrained suffix match and suffix replacement rule. If a suffix of the input string exactly matches match then the replacement is suffixed instead to the non-matching prefix part of the input string.

`?match:replacements`

  A constrained suffix match and suffix replacement rule. If a suffix of the input string exactly matches match and the remaining prefix does not contain a dot, then the replacement is suffixed instead to the non-matching prefix part of the input string.

If the resultant string, after applying all of the rules, contains `+` characters, it is deemed to be a search path of the form `prefix+suffix+suffix`. A search path list of names to try looking up is constructed by each suffix in order being appended to prefix

#### Examples

##### A common final rule in a ruleset.

    *.:

This simply removes trailing dots. The djbwares DNS client library does not need the trailing dots after qualification, as the output, search path, list of one or more names is taken to be the "fully-qualified" name(s) to actually look up.

##### A simple 1-result qualification for dot-less names.

    ?:.example.org

If the input string is `curtin`, the resultant name is `curtin.example.org`. But this rule will not apply if the input string is `saint.james` or `curtin.`.

This is the search path behaviour that some users expect, and is thus the form into which the `LOCALDOMAIN` environment variable and `search` directives in resolv.conf 5 are converted when they have 1 entry, even though it is not actually traditional DNS client library behaviour.

##### A search path for dot-less names.

    ?:.intranet.example.org+.example.org+

If the input string is `curtin`, the resultant search list is `curtin.intranet.example.org` then `curtin.example.org` then `curtin`. But this rule will not apply if the input string is `saint.james` or `curtin.`.

This rule yields the bogus top-level domain `curtin` if the input string is `curtin`, which is one way in which the world often generates bogus query traffic to the "`.`" content DNS servers (or, worse, happens to match one of the lesser-known global top-level domains unexpectedly).

Converting the `LOCALDOMAIN` environment variable and `search` directives in resolv.conf 5 when they have more than 1 entry does not append an extra final blank search path beyond the search path that is given. But, rather, it yields the form:

    ?:.intranet.example.org+.example.org

If the input string is `curtin`, the resultant search list is `curtin.intranet.example.org` then `curtin.example.org`.

Search paths with more than 1 entry are usually poor ideas, as they lead to finding names in subdomains or superdomains that can surprise users. Users generally expect 1 domain name as the single domain name that is appended by name qualification.

##### A search path for any names (dots or no) that searches multiple parts of an organization.

    *:.work.example.org+.school.example.org+

If the input string is `curtin`, the resultant search list is `curtin.work.example.org` then `curtin.school.example.org` then `curtin`. If the input string is `saint.james`, the resultant search list is `saint.james.work.example.org` then `saint.james.school.example.org` then `saint.james`.

There is a common misconception amongst users that names that have an internal dot, rather than a trailing dot, are "fully qualified"; even though this has not in fact traditionally been the case, and (rather) this form of search path is in fact how other DNS client libraries traditionally worked for many years. Such users will be surprised by `example.com` becoming `example.com.work.example.org` and `example.com.school.example.org` here before `example.com` is finally tried.
This rule is also applied if the input string is `saint.james.` or `curtin.`, which definitely surprises many users, even the ones that thought that they knew to use trailing dots.

In general, despite being the traditional DNS client library behaviour of yore, this is almost never a good rule.

##### A superdomain rename for subdomain names with and without dots.

    *.example.org:.example.net

If the input string is `saint.james.example.org`, the resultant name is `saint.james.example.net`. However, if the input string is `saint.james.example.org.`, this rule does not apply, following the usual convention that a trailing dot indicates an already qualified name.

Matching commonly happens at a dot as in this example, but does not actually have to.

##### A collapse of all subdomains onto a single name.

    -.example.com:example.com

If the input string is `smith.example.com` or `meyers.example.com`, the resultant name is simply `example.com`. Again however, if the input string is instead `smith.example.com.` or `meyers.example.com.`, this rule does not apply, following the usual convention. The input string `example.com` sans any subdomain is also not matched by this rule; a separate extra `=` rule being necessary for that if appropriate.

The most common real world use for this are the subdomains of `localhost.` and of `invalid.` all being their equivalents.

    -.localhost:localhost
    -.invalid:invalid

But those are already special-use domain names handled by the DNS client library.

## See also

dnsq 1
dnsqr 1
dnsip 1
dnsmx 1
dnsname 1
dnsnamex 1
dnsns 1
dnstxt 1
dnsipq 1
host 1

## History

The `DNSCACHEIP`, `DNSREWRITEFILE`, and `LOCALDOMAIN` environment variables and limited compatibililty processing of resolv.conf 5 were originally part of Daniel J. Bernstein's djbdns toolset, begun in 1999.

At the time, many of the additional systems and special-use domain names had not even been invented. The formal documentation of conventional DNS results for subdomains of `localhost.` and `invalid.` did not occur until 2013, for instance.

The additional environment variables and mechanisms for special-use domain names were added in 2025.

The caution against using search paths is also Bernstein's, and remains as true today as it did then.

## Author

Original code by Daniel J. Bernstein. Documentation and modernizations by Jonathan de Boyne Pollard.