tinydns — a general-purpose content DNS server using the UDP protocol
tinydns
tinydns is a content DNS server that speaks the DNS/UDP protocol. It accepts DNS queries from hosts around the Internet, and responds with locally configured information from a static database. It runs in a system-secured environment and requires no privileges nor any filesystem access other than read access to its static database. It logs a record of its operation simply to its standard error.
tinydns respects a location code system encoded in its database and differentiates amongst requesting clients according to their locations, determined by their IP addresses. It is designed to be Internet-facing; and its normal use is for answering Internet DNS queries from hosts around the Internet. It can also be employed locally on a LAN, or even locally within a single machine, for providing information to hosts on an intranet.
It is possible to run multiple entirely isolated instances on a single machine, each with their own static databases and listening on particular IP addresses for different purposes. It is conversely possible to run multiple instances on a single machine, each listening on particular IP addresses, all sharing a single database.
Normally tinydns is run via a server program such as udp-socket-listen to listen for DNS/UDP queries.
It understands the LISTEN_PID and LISTEN_FDS environment variable convention for having an already-listening socket passed to it by such a program, and uses the last open file descriptor in the list that refers to a UDP/IPv4 socket.
If no such open file descriptor is provided it falls back to opening its own UDP/IPv4 socket, bound to port 53 of the IP address given by the value of the IP environment variable.
It does not handle DNS/TCP.
tinydns rejects (sending a reply with an error code) zone-transfer requests, inverse queries, and packets that contain anything other than a single query. It does not answer (single) non-Internet-class queries, or truncated packets.
tinydns answers queries as specified by data.cdb, a binary file in its root directory created by tinydns-data(1).
It does not write to this file, or attempt to create it.
tinydns supports clients that negotiate large DNS/UDP response packet sizes with EDNS0. When it has to truncate responses, when the conventional/EDNS0-negotiated response size is not large enough, it truncates all answer, authority, and additional section resource records.
tinydns includes NS records with answers to most queries.
This increases DNS packet sizes, but it draws queries away from parent servers, and reduces the frequency of long DNS delays.
With the default cache times, a client that uses a normal record at least once every day will always have the corresponding NS records cached and will never have to talk to parent servers.
If a record set has ending time ("time to die") for the information; tinydns dynamically adjusts the TTLs that it publishes so that the records are not cached for more than a few seconds past the ending time.
SOA resource records inform tinydns what requests to answer.
It will only answer at all for domain names where there is a SOA resource record at or above that domain name in the namespace.
There can be many SOA resource records for a domain, as the result of many . lines in the source data file.
tinydns will return only one SOA record per domain when the request is actually for a domain's SOA resource record set.
NS resource records inform tinydns about delegation points (when they are not accompanied by SOA resource records).
It will always answer with a delegation response for domain names at or below a delegation point in the namespace.
tinydns returns IP addresses (i.e. A or AAAA records generated from + or = or @ or . or & lines in the source data file) in a random order in the answer section.
If there are more than 8 records, it returns a random list of 8.
(People used to use this as a mechanism for spreading server load across multiple machines; albeit that this was highly flawed, for several reasons.)
tinydns supports wildcards of the form *..
Information for fqdn*. is provided for every domain name ending with fqdn., except names that have their own records and names that are covered by more specific wildcards.
fqdn
For example, the lines (as written in the original database source file)
+pink.floyd.u.heaven.af.example:203.0.113.4 +*.u.heaven.af.example:203.0.113.200
have the same effect as
+pink.floyd.u.heaven.af.example:203.0.113.4 +joe.u.heaven.af.example:203.0.113.200 +bill.u.heaven.af.example:203.0.113.200 +floyd.u.heaven.af.example:203.0.113.200 +ishtar.u.heaven.af.example:203.0.113.200 +joe.bob.u.heaven.af.example:203.0.113.200 +sally.floyd.u.heaven.af.example:203.0.113.200 +post.pink.floyd.u.heaven.af.example:203.0.113.200
and so on.
As another example, the lines
+pink.floyd.u.heaven.af.example:203.0.113.4 @*.u.heaven.af.example::mail.heaven.af.example
have the same effect as
+pink.floyd.u.heaven.af.example:203.0.113.4 @joe.u.heaven.af.example::mail.heaven.af.example @bill.u.heaven.af.example::mail.heaven.af.example @floyd.u.heaven.af.example::mail.heaven.af.example @ishtar.u.heaven.af.example::mail.heaven.af.example @joe.bob.u.heaven.af.example::mail.heaven.af.example @sally.floyd.u.heaven.af.example::mail.heaven.af.example @post.pink.floyd.u.heaven.af.example::mail.heaven.af.example
and so on.
Notice that the wildcard does not apply to pink.floyd.u.heaven.af.example, because that name has its own records.
When it starts tinydns changes its root to the directory specified by the ROOT environment variable, and drops privileges to run as the user ID and group ID specified by the UID and GID environment variables.
The latter can be set up with envuidgid(1).
ANY queries used to be used by a few mail systems as a shortcut for performing A and MX queries in one go, although were never guaranteed to work that way, it just being an accident of implementation of ISC BIND in the 1990s.
They are nowadays, instead, a common attack on the Domain Name System; as documented in RFC8482 in January 2019.
tinydns does not return any data other than CNAMEs from the data file in response to an ANY query.
If the domain name exists and has no CNAMEs, they are answered with a single synthesized HINFO record.
tinydns has always minimized other "amplification" attacks, where a client falsifies its reply IP address to direct responses to a third party, or asks about third parties in order to generate back-end query resolution traffic to those third parties.
When there is no SOA resource record at or above a queried domain name, tinydns simply sends no response at all.
And it neither does query resolution, nor has a back end where it performs any kind of transaction with another server.
Sending no response at all to non-Internet-class queries is a privacy measure.
ISC's BIND made this into a way to fingerprint DNS servers by responding with synthetic internal program version information to TXT type queries in the CHAOS class domain names such as version.bind.
Others even extended this into a more generic version.server domain name.
tinydns never imitated this; and has never given out internal version information.
ChaosNet was a short-lived Local Area Network protocol at MIT in the 1970s; and BIND simply repurposed what had by the late 1980s become a defunct query class. The only other actually assigned non-Internet query class, in the 21st century, is Hesiod. The only use of non-Internet query classes in the wild is for fingerprinting people's versions of ISC's BIND, Microsoft's DNS server, Knot DNS, PowerDNS, et al..
tinydns can be used for providing a private copy of the DNS "root", or indeed any other, data for reducing query traffic that goes off-organization, off-LAN, or even off-machine.
This is just a matter of obtaining those data, which are officially published for such use by several domain owners including the ICANN root, removing any overlaps/duplications of other data, and incorporating them into the static database file.
It is in fact the very same process as providing "secondary" service for a domain, sans the step of listing the tinydns instance as one of the servers for the domain in a . record in the database.
For best results, such data should be tagged with a location code that limits their visibility to only hosts within the organization/LAN, or to the local machine; or the instance of tinydns should not be listening on an Internet-routable IP address. tinydns does not leak location-tagged data. Answers given to clients in one location are not affected by the presence of data tagged for another location.
More specifically:
If tinydns has a location-tagged copy of the DNS "root" for on-intranet/LAN/machine use, this will not cause it to therefore answer all queries from off-intranet/LAN/machine clients just because there is a SOA resource record set for the . domain name in the database.
A single instance of tinydns can serve a private "root" to one set of locations whilst still being Internet-facing.
tinydns was originally part of Daniel J. Bernstein's djbdns toolset in 1999. It incorporated the functionality of pickdns(1), rendering that obsolete, in 2001.
tinydns ceased responding in the old style to ANY queries in March 2019.
It ceased similarly treating the ANY class (as opposed to type) as a wildcard in July 2025.
It ceased responding to non-Internet-class queries in August 2025; prior to which it replied with an error response.
tinydns gained EDNS0 capability in 2025.