This is a reference manual with all of MaraDNS' manual pages
The following manuals are here:
- Deadwood man page
- askmara man page
- blockHashMake man page
- blockHashRead man page
- coLunacyDNS man page
- csv1 man page
- csv2 man page
- csv2_txt man page
- duende man page
- fetchzone man page
- getzone man page
- maradns man page
- mararc man page
- zoneserver man page
Deadwood - A fully recursive caching DNS resolver
Deadwood is a fully recursive DNS cache. This is a DNS server with the following features:
-
Full support for both DNS recursion and DNS forwarding caching
-
Small size and memory footprint suitable for embedded systems
-
Simple and clean codebase
-
Secure design
-
Spoof protection: Strong cryptography used to determine the Query ID and source port
-
Ability to read and write the cache to a file
-
Dynamic cache that deletes entries not recently used
-
Ability to use expired entries in the cache when it is impossible to contact upstream DNS servers.
-
IPv6 support can be compiled in if desired
-
Both DNS-over-UDP and DNS-over-TCP are handled by the same daemon
-
Built-in dnswall functionality
-
The ability to assign names to IPv4 IPs as specified in one's dwood3rc file.
-
The ability to quickly load and use a large blocklist of names to not resolve.
Deadwood has a single optional command line argument: The location of the configuration file that Deadwood uses, specified with the "-f" flag. If this is not defined, Deadwood uses the file "/etc/dwood3rc" as the configuration file.
In other words, invoking Deadwood as Deadwood will cause Deadwood to use /etc/dwood3rc as the configuration file; invoking Deadwood as Deadwood -f foobar will cause Deadwood to use the file "foobar" in the current working directory (the directory one is in when starting Deadwood) as the configuration file.
The Deadwood configuration file is modeled after Python 2's syntax. However, since Python 2 is no longer supported by the Python Software Foundation, and since Deadwood configuration files can sometimes fail to parse in Python 3, Deadwood does not strictly follow Python 2 syntax.
In particular, leading whitespace is allowed in Deadwood configuration files.
Deadwood has three different parameter types:
- Numeric parameters. Numeric parameters must not be surrounded by quotes, such as this example:
filter_rfc1918 = 0
If a numeric parameter is surrounded by quotes, the error message "Unknown dwood3rc string parameter" will appear.
- String parameters. String parameters must be surrounded by quotes, such as in this example:
bind_address = "127.0.0.1"
- Dictionary parameters. All dictionary parameters must be initialized before use, and dictionary parameters must have both the dictionary index and the value for said index surrounded by quotes, such as in this example:
upstream_servers = {}
upstream_servers["."]="8.8.8.8, 8.8.4.4"
All dwood3rc parameters except the following are numeric parameters:
-
bind_address (string)
-
blocked_hosts_hash_file (string)
-
cache_file (string)
-
chroot_dir (string)
-
ip4 (dictionary)
-
ip6 (dictionary)
-
ip_blacklist (string)
-
ip_blocklist (string)
-
ipv4_bind_addresses (string)
-
random_seed_file (string)
-
recursive_acl (string)
-
root_servers (dictionary)
-
source_ip4 (string)
-
upstream_servers (dictionary)
The Deadwood configuration file supports the following parameters:
If this numeric parameter has a value of 1, we allow a blocked hosts hash file to have a key which is 0. Otherwise, if a blocked hosts file has a 0 key, Deadwood will terminate when loading the blocked hosts file with the error message "Zero key block hash not allowed by default".
There is a security risk if we allow a blocked hosts file to have a 0 key: An attacker with access to a recursive instance of Deadwood could have Deadwood use more resources than necessary if they know the block hash file being used. Since the block hash file is read only, hash flooding attacks are not possible, but an attacker could form queries which use more resources to resolve as not being present in the block hash.
Deadwood should never be an open recursor and this attack is limited in scope. But be aware of the risks before setting this parameter to 1.
This is the IP (or possibly IPv6) address we bind to.
A blocked hosts hash file allows Deadwood to block a large number of
host names while using relatively little memory: While using a list of
over 200,000 hosts to block in a dwood3rc
file uses over 200
megabytes of memory, the same list in a block hash file uses only 7
megabytes of memory.
The block hash file is in a special binary format so that a large number of host names can be blocked quickly using little memory.
This parameter, if set, is the filename for a block hash file. The file
will be located in the directory set by chroot_dir
(usually,
/etc/deadwood
). The file name can have lower case letters, the '-'
character (dash), the '_' character (underscore), the '.' character
(dot or period), and the '/' character (slash). If the file name has
the '.' character (dot/period) in it, it can not have a '/' (slash)
after the '.' (dot).
The blockHashMake
program generates the block hash file. The contents
of a block hash file can be looked at and read using the
blockHashRead
program. See the man pages blockHashMake (1) and
blockHashRead (1) for more details.
Block hash files have wildcard support. For example, if "example.com" is in the block hash file, then deadwood will block "example.com", "anyname.example.com", "anything.else.example.com", "12345.example.com", and so on.
Note that wildcards only work for domain names which are one, two, or three labels long in the database. If "really.bad.example.com" is in the database, "buzz.really.bad.example.com" will not match, since "really.bad.example.com" has four (i.e. more than three) labels.
One usable block hash file is available at the repo at https://github.com/samboy/BlockHash
This is the filename of the file used for reading and writing the cache to disk; this string can have lowercase letters, the '-' symbol, the '' symbol, and the '/' symbol (for putting the cache in a subdirectory). All other symbols become a '' symbol.
This file is read and written as the user Deadwood runs as.
This is the directory the program will run from.
This affects behavior in Deadwood 2.3, but has no effect in Deadwood 3. This variable is only here so Deadwood 2 rc files can run in Deadwood 3.
This is the port Deadwood binds to and listens on for incoming connections. The default value for this is the standard DNS port: port 53
When this has a value of 1, a number of different IP ranges are not allowed to be in DNS A replies:
-
192.168.x.x
-
172.[16-31].x.x
-
10.x.x.x
-
127.x.x.x
-
169.254.x.x
-
224.x.x.x
-
0.0.x.x
If one of the above IPs is detected in a DNS reply, and filter_rfc1918 has a value of 1, Deadwood will return a synthetic "this host does not reply" response (a SOA record in the NS section) instead of the A record.
The reason for this is to provide a "dnswall" that protects users for some kinds of attacks, as described at http://crypto.stanford.edu/dns/
Please note that Deadwood only provides IPv4 "dnswall" functionality and does not help protect against IPv6 answers. If protection against certain IPv6 AAAA records is needed, either disable all AAAA answers by setting reject_aaaa to have a value of 1, or use an external program to filter undesired IPv4 answers (such as the dnswall program).
The default value for this is 1
When this is set to 0, Deadwood sends no reply back to the client (when the client is a TCP client, Deadwood closes the TCP connection) when a UDP query is sent upstream and the upstream DNS never sends a reply.
When this is set to 1, Deadwood sends a SERVER FAIL back to the client when a UDP query is sent upstream and the upstream DNS never sends a reply.
The default value for this is 1
When this has a value of 0, Deadwood sends no reply when a UDP query is sent and the server is overloaded (has too many pending connections); when it has a value of 1, Deadwood sends a SERVER FAIL packet back to the sender of the UDP query. The default value for this is 1.
This used to be used for Deadwood's internal hash generator to keep the hash generator somewhat random and immune to certain types of attacks. In Deadwood 3.0, entropy for the hash function is created by looking at the contents of /dev/urandom (secret.txt on Windows machines) and the current timestamp. This parameter is only here so older configuration files do not break in Deadwood 3.0.
This is a dictionary variable which allows us to have given names resolve to bogus IPv4 addresses. Here, we have the name "maradns.foo" resolve to "10.10.10.10" and "kabah.foo" resolve to "10.11.11.11", regardless of what real values these DNS records may have:
ip4 = {}
ip4["maradns.foo."] = "10.10.10.10"
ip4["kabah.foo."] = "10.11.11.11"
Note that a given name can only resolve to a single IP, and that the records have a fixed TTL of 30 seconds.
It is also possible to use ip4 to set up a blocklist by using "X" for the IP. When this is done, an IPv4 request for a given hostname results in a synthetic "this name does not exist" response. In addition, the corresponding IPv6 request will also return that "name does not exist" reply. For example:
ip4 = {}
ip4["evil.example.com."] = "X"
Here, both the IPv4 and the IPv6 query for "evil.example.com" will not resolve in Deadwood.
Like ip4, ip6 uses a similar syntax to have bogus IPv6 addresses. We don't use standard notation for IPv6 addresses. Instead, we we use 32-character hex addresses (case insensitive); to make it easier to count long strings of "0"s, the "_" acts like a 0; we also ignore "-" (dash) and " " (space) in ip6 strings. Here is an example:
ip6 = {}
ip6["maradns.foo."] = "20010db84d617261444e530000001234"
ip6["kabah.foo."] = "2001-0DB8-4D61-7261 444E-5300-__00-2345"
This is a list of IPs that we do not allow to be in the answer to a DNS request. The reason for this is to counteract the practice some ISPs have of converting a "this site does not exist" DNS answer in to a page controlled by the ISP; this results in possible security issues.
This parameter only accepts individual IPs, and does not use netmasks.
Note that this parameter used to be called ip_blacklist; while the ip_blacklist name still works as before, ip_blocklist is the current name.
The user-id Deadwood runs as. This can be any number between 10 and 16777216; the default value is 707 (a system UID which should be unused). This value is not used on Windows systems.
The group-id Deadwood runs as. This can be any number between 10 and 16777216; the default value is 707. This value is not used on Windows systems.
Whether resource record rotation is enabled. If this has a value of 1, resource record rotation is enabled, otherwise resource record rotation is disabled.
Resource record rotation is usually desirable, since it allows DNS to act like a crude load balancer. However, on heavily loaded systems it may be desirable to disable it to reduce CPU usage.
The reason for the unusual name for this variable is to retain compatibility with MaraDNS mararc files.
The default value is 1: Resource record rotation enabled.
The maximum number of simultaneous clients we process at the same time for the same query.
If, while processing a query for, say, "example.com.", another DNS client sends to Deadwood another query for example.com, instead of creating a new query to process example.com, Deadwood will attach the new client to the same query that is already "in flight", and send a reply to both clients once we have an answer for example.com.
This is the number of simultaneous clients a given query can have. If this limit is exceeded, subsequents clients with the same query are refused until an answer is found. If this has a value of 1, we do not merge multiple requests for the same query, but give each request its own connection.
The default value is 8.
The maximum amount of time we will keep an entry in the cache, in seconds (also called "Maximum TTL").
This is the longest we will keep an entry cached. The default value for this parameter is 86400 (one day); the minimum value is 300 (5 minutes) and the maximum value this can have is 7776000 (90 days).
The reason why this parameter is here is to protect Deadwood from attacks which exploit there being stale data in the cache, such as the "Ghost Domain Names" attack.
The maximum number of elements our cache is allowed to have. This is a number between 32 and 16,777,216; the default value for this is 1024. Note that, if writing the cache to disk or reading the cache from disk, higher values of this will slow down cache reading/writing.
The amount of memory each cache entry uses is variable depending on the operating system used and the size of memory allocation pages assigned. In Windows XP, for example, each entry uses approximately four kilobytes of memory and Deadwood has an overhead of approximately 512 kilobytes. So, if there are 512 cache elements, Deadwood uses approximately 2.5 megabytes of memory, and if there are 1024 cache elements, Deadwood uses approximately 4.5 megabytes of memory. Again, these numbers are for Windows XP and other operating systems will have different memory allocation numbers.
Please note that, as of Deadwood 3.5.0004, is is no longer needed to increase maximum_cache_elements to store upstream_server and root_server entries.
This is the maximum number of pending remote UDP connections Deadwood can have. The default value for this is 1024.
This is the number of allowed open TCP connections. Default value: 8
The minimum amount of time we will keep an entry in the cache, in seconds (also called "Minimum TTL").
The number of times we retry to send a query upstream before giving up. If this is 0, we only try once; if this is 1, we try twice, and so on, up to 32 retries. Note that each retry takes timeout_seconds seconds before we retry again. Default value: 5
The RR type we send to resolve glueless records. This should always be 1 (A; i.e. IPv4 DNS servers). This should never be ANY, see RFC8482. This should not be any other value, since only A glueless NS referrals have ever been tested with Deadwood.
The reason why this exists is because, often times in DNS, we get a reply like "The name server for this foo.example.com and no I do not have the IP for foo.example.com" when recursively solving an answer. So, the question is this: Is foo.example.com an IPv4 DNS server, an IPv6 server, or both?
On today's internet (mid-2020, during the COVID-19 crisis), the answer is that the name server in question is only on the IPv4 Internet. IPv6 is now mainstream (e.g. my ISP gives me a /64 and I no longer have to tunnel through he.net to try out IPv6), but most servers are still IPv4 only (e.g. my domains are only on IPv4, and amazon.com does not have an IPv6 address).
The reason this parameter exists is because, when I was writing the recursive code for Deadwood, I was thinking of a future where IPv6 is prevalent enough that we would have DNS servers with only IPv6 addresses, and glueless NS referrals (the "foo.example.com" case above) would point to servers with IPv6, but not IPv4, addresses.
That day may yet come, but preparing Deadwood to still be a viable DNS server when that day comes will require more than changing the RR type sent when it gets a glueless NS referral.
This is a file that contains random numbers, and is used as a seed for the cryptographically strong random number generator. Deadwood will try to read 256 bytes from this file (the RNG Deadwood uses can accept a stream of any arbitrary length).
Note that the hash compression function obtains some of its entropy before parsing the mararc file, and is hard-coded to get entropy from /dev/urandom (secret.txt on Windows systems). Most other entropy used by Deadwood comes from the file pointed to by random_seed_file.
The lowest numbered port Deadwood is allowed to bind to; this is a random port number used for the source port of outgoing queries, and is not 53 (see dns_port above). This is a number between 1025 and 32767, and has a default value of 15000. This is used to make DNS spoofing attacks more difficult.
The number of ports Deadwood binds to for the source port for outgoing connections; this is a power of 2 between 256 and 32768. This is used to make DNS spoofing attacks more difficult. The default value is 4096.
This is a list of who is allowed to use Deadwood to perform DNS recursion, in "ip/mask" format. Mask must be a number between 0 and 32 (for IPv6, between 0 and 128). For example, "127.0.0.1/8" allows local connections.
If this has a value of 1, a bogus SOA "not there" reply is sent whenever an AAAA query is sent to Deadwood. In other words, every time a program asks Deadwood for an IPv6 IP address, instead of trying to process the request, when this is set to 1, Deadwood pretends the host name in question does not have an IPv6 address.
This is useful for people who aren't using IPv6 but use applications (usually *NIX command like applications like "telnet") which slow things down trying to find an IPv6 address.
This has a default value of 0. In other words, AAAA queries are processed normally unless this is set.
When this has the default value of 1, MX queries are silently dropped with their IP logged. A MX query is a query that is only done by a machine if it wishes to be its own mail server sending mail to machines on the internet. This is a query an average desktop machine (including one that uses Outlook or another mail user agent to read and send email) will never make.
Most likely, if a machine is trying to make a MX query, the machine is being controlled by a remote source to send out undesired "spam" email. This in mind, Deadwood will not allow MX queries to be made unless reject_mx is explicitly set with a value of 0.
Before disabling this, please keep in mind that Deadwood is optimized to be used for web surfing, not as a DNS server for a mail hub. In particular, the IPs for MX records are removed from Deadwood's replies and Deadwood needs to perform additional DNS queries to get the IPs corresponding to MX records, and Deadwood's testing is more geared for web surfing (almost 100% A record lookup) and not for mail delivery (extensive MX record lookup).
If this has a value of 1, a bogus SOA "not there" reply is sent whenever a PTR query is sent to Deadwood. In other words, every time a program asks Deadwood for "reverse DNS lookup" -- the hostname for a given IP address -- instead of trying to process the request, when this is set to 1, Deadwood pretends the IP address in question does not have a hostname.
This is useful for people who are getting slow DNS timeouts when trying to perform a reverse DNS lookups on IPs.
This has a default value of 0. In other words, PTR queries are processed normally unless this is set.
If this is set to 1, Deadwood will try to send an expired record to the user before giving up. If it is 0, we don't. Default value: 1
If this is set to 1, Deadwood will not allow ANY or HINFO queries, sending a RFC8482 response if one is given to Deadwood. If this is 0, ANY and HINFO queries are allowed. Default value: 1
If ANY queries are enabled, since Deadwood does not support EDNS nor DNS-over-TCP for upstream queries, Deadwood may not get meaningful replies from upstream servers.
This is a list of root servers; its syntax is identical to upstream_servers (see below). This is the type of DNS service ICANN, for example, runs. These are servers used that do not give us complete answers to DNS questions, but merely tell us which DNS servers to connect to to get an answer closer to our desired answer.
As of Deadwood 3.5.0004, it is no longer needed to increase maximum_cache_elements to store root_server entries.
Please be aware that this parameter is deprecated. While there are no plans to remove this parameter, Deadwood is no longer being updated to resolve DNS resolution issues when using root_servers to resolve names on the internet. Please use upstream_servers instead.
With certain complicated networks, it may be desirable to set the source IP of queries sent to upstream or root DNS servers. If so, set this parameter to have the dotted decimal IPv4 address to use when sending IPv4 queries to an upstream DNS server.
Use this parameter with caution; Deadwood can very well become non-functional if one uses a source IPv4 address which Deadwood is not bound to.
In order to enable DNS-over-TCP, this variable must be set and have a value of 1. Default value: 0
This is how long Deadwood will wait before giving up and discarding a pending UDP DNS reply. The default value for this is 1, as in 1 second, unless Deadwood was compiled with FALLBACK_TIME enabled.
How long to wait on an idle TCP connection before dropping it. The default value for this is 4, as in 4 seconds.
Whether TTL aging is enabled; whether entries in the cache have their TTLs set to be the amount of time the entries have left in the cache.
If this has a value of 1, TTL entries are aged. Otherwise, they are not. The default value for this is 1.
This is the port Deadwood uses to connect or send packets to the upstream servers. The default value for this is 53; the standard DNS port.
This is a list of DNS servers that the load balancer will try to contact. This is a dictionary variable (array indexed by a string instead of by a number) instead of a simple variable. Since upstream_servers is a dictionary variable, it needs to be initialized before being used.
Deadwood will look at the name of the host that it is trying to find the upstream server for, and will match against the longest suffix it can find.
For example, if someone sends a query for "www.foo.example.com" to Deadwood, Deadwood will first see if there is an upstream_servers variable for "www.foo.example.com.", then look for "foo.example.com.", then look for "example.com.", then "com.", and finally ".".
Here is an example of upstream_servers:
upstream_servers = {} # Initialize dictionary variable
upstream_servers["foo.example.com."] = "192.168.42.1"
upstream_servers["example.com."] = "192.168.99.254"
upstream_servers["."] = "10.1.2.3, 10.1.2.4"
In this example, anything ending in "foo.example.com" is resolved by the DNS server at 192.168.42.1; anything else ending in "example.com" is resolved by 192.168.99.254; and anything not ending in "example.com" is resolved by either 10.1.2.3 or 10.1.2.4.
Important: the domain name upstream_servers points to must end in a "." character. This is OK:
upstream_servers["example.com."] = "192.168.42.1"
But this is not OK:
upstream_servers["example.com"] = "192.168.42.1"
The reason for this is because BIND engages in unexpected behavior when a host name doesn't end in a dot, and by forcing a dot at the end of a hostname, Deadwood doesn't have to guess whether the user wants BIND's behavior or the "normal" behavior.
If neither root_servers nor upstream_servers are set, Deadwood sets upstream_servers to use the https://quad9.net servers, as follows:
9.9.9.9
149.112.112.112
Please note that, as of Deadwood 3.5.0004, is is no longer needed to increase maximum_cache_elements to store upstream_server entries.
This determines how many messages are logged on standard output; larger values log more messages. The default value for this is 3.
Deadwood uses a standard ip/netmask formats to specify IPs. An ip is in dotted-decimal format, e.g. "10.1.2.3" (or in IPv6 format when IPv6 support is compiled in).
The netmask is used to specify a range of IPs. The netmask is a single number between 1 and 32 (128 when IPv6 support is compiled in), which indicates the number of leading "1" bits in the netmask.
10.1.1.1/24 indicates that any ip from 10.1.1.0 to 10.1.1.255 will match.
10.2.3.4/16 indicates that any ip from 10.2.0.0 to 10.2.255.255 will match.
127.0.0.0/8 indicates that any ip with "127" as the first octet (number) will match.
The netmask is optional, and, if not present, indicates that only a single IP will match.
DNS-over-TCP needs to be explicitly enabled by setting tcp_listen to 1.
Deadwood extracts useful information from UDP DNS packets marked truncated which almost always removes the need to have DNS-over-TCP. However, Deadwood does not cache DNS packets larger than 512 bytes in size that need to be sent using TCP. In addition, DNS-over-TCP packets which are "incomplete" DNS replies (replies which a stub resolver can not use, which can be either a NS referral or an incomplete CNAME reply) are not handled correctly by Deadwood.
Deadwood has support for both DNS-over-UDP and DNS-over-TCP; the same daemon listens on both the UDP and TCP DNS port.
Only UDP DNS queries are cached. Deadwood does not support caching over TCP; it handles TCP to resolve the rare truncated reply without any useful information or to work with very uncommon non-RFC-compliant TCP-only DNS resolvers. In the real world, DNS-over-TCP is almost never used.
It is possible to have Deadwood, while parsing the dwood3rc file, read other files and parse them as if they were dwood3rc files.
This is done using execfile. To use execfile, place a line like this in the dwood3rc file:
execfile("path/to/filename")
Where path/to/filename is the path to the file to be parsed like a dwood3rc file.
All files must be in or under the directory /etc/deadwood/execfile. Filenames can only have lower-case letters and the underscore character ("_"). Absolute paths are not allowed as the argument to execfile; the filename can not start with a slash ("/") character.
If there is a parse error in the file pointed to by execfile, Deadwood will report the error as being on the line with the execfile command in the main dwood3rc file. To find where a parse error is in the sub-file, use something like "Deadwood -f /etc/deadwood/execfile/filename" to find the parse error in the offending file, where "filename" is the file to to parsed via execfile.
This server can also be optionally compiled to have IPv6 support. In order to enable IPv6 support, add '-DIPV6' to the compile-time flags. For example, to compile this to make a small binary, and to have IPv6 support:
export FLAGS='-Os -DIPV6'
make
Deadwood is a program written with security in mind.
In addition to use a buffer-overflow resistant string library and a coding style and SQA process that checks for buffer overflows and memory leaks, Deadwood uses a strong pseudo-random number generator (The 32-bit version of RadioGatun) to generate both the query ID and source port. For the random number generator to be secure, Deadwood needs a good source of entropy; by default Deadwood will use /dev/urandom to get this entropy. If you are on a system without /dev/urandom support, it is important to make sure that Deadwood has a good source of entropy so that the query ID and source port are hard to guess (otherwise it is possible to forge DNS packets).
The Windows port of Deadwood includes a program called "mkSecretTxt.exe" that creates a 64-byte (512 bit) random file called "secret.txt" that can be used by Deadwood (via the "random_seed_file" parameter); Deadwood also gets entropy from the timestamp when Deadwood is started and Deadwood's process ID number, so it is same to use the same static secret.txt file as the random_seed_file for multiple invocations of Deadwood.
Note that Deadwood is not protected from someone on the same network viewing packets sent by Deadwood and sending forged packets as a reply.
To protect Deadwood from certain possible denial-of-service attacks, it is best if Deadwood's prime number used for hashing elements in the cache is a random 31-bit prime number. The program RandomPrime.c generates a random prime that is placed in the file DwRandPrime.h that is regenerated whenever either the program is compiled or things are cleaned up with make clean. This program uses /dev/urandom for its entropy; the file DwRandPrime.h will not be regenerated on systems without /dev/urandom.
On systems without direct /dev/urandom support, it is suggested to see if there is a possible way to give the system a working /dev/urandom. This way, when Deadwood is compiled, the hash magic number will be suitably random.
If using a precompiled binary of Deadwood, please ensure that the system has /dev/urandom support (on Windows system, please ensure that the file with the name secret.txt is generated by the included mkSecretTxt.exe program); Deadwood, at runtime, uses /dev/urandom (secret.txt in Windows) as a hardcoded path to get entropy (along with the timestamp) for the hash algorithm.
Deadwood's configuration file format supports two kinds of comments:
# This is a comment
Here, a comment starts with the # character and continues until the end of the line. In some circumstances, a comment can start after a variable is set, for example:
bind_address="127.0.0.1" # IP we bind to
The second comment type supports multi-line comments. For example:
_rem={}
_rem={ #_rem --[=[
"""
We are now in a multi-line comment.
This allows a long explanation to be
in a Deadwood configuration file
""" # ]=]
}
The actual format is _rem={ at the start of a line, which begins a multi-line comment. The comment continues until a } is seen. The reason for this unusual format is that it allows a Deadwood configuration file to have multi-line comments in a form which are compatible with both Lua and Python, as can be seen in the above example.
Deadwood does not have any built-in daemonization facilities; this is handled by the external program Duende or any other daemonizer.
Here is an example dwood3rc configuration file:
# This is an example deadwood rc file
# Note that comments are started by the hash symbol
bind_address="127.0.0.1" # IP we bind to
# The following line is disabled by being commented out
#bind_address="::1" # We have optional IPv6 support
# Directory we run program from (not used in Win32)
chroot_dir = "/etc/deadwood"
# The following upstream DNS servers are Google's
# (as of December 2009) public DNS servers. For
# more information, see the page at
# http://code.google.com/speed/public-dns/
#
# If neither root_servers nor upstream_servers are set,
# Deadwood will use the default ICANN root servers.
#upstream_servers = {}
#upstream_servers["."]="8.8.8.8, 8.8.4.4"
# Who is allowed to use the cache. This line
# allows anyone with "127.0" as the first two
# digits of their IP to use Deadwood
recursive_acl = "127.0.0.1/16"
# Maximum number of pending requests
maxprocs = 2048
# Send SERVER FAIL when overloaded
handle_overload = 1
maradns_uid = 99 # UID Deadwood runs as
maradns_gid = 99 # GID Deadwood runs as
maximum_cache_elements = 60000
# If you want to read and write the cache from disk,
# make sure chroot_dir above is readable and writable
# by the maradns_uid/gid above, and uncomment the
# following line.
#cache_file = "dw_cache"
# If your upstream DNS server converts "not there" DNS replies
# in to IPs, this parameter allows Deadwood to convert any reply
# with a given IP back in to a "not there" IP. If any of the IPs
# listed below are in a DNS answer, Deadwood converts the answer
# in to a "not there"
#ip_blocklist = "10.222.33.44, 10.222.3.55"
# By default, for security reasons, Deadwood does not allow IPs in
# the 192.168.x.x, 172.[16-31].x.x, 10.x.x.x, 127.x.x.x,
# 169.254.x.x, 224.x.x.x, or 0.0.x.x range. If using Deadwood
# to resolve names on an internal network, uncomment the
# following line:
#filter_rfc1918 = 0
Deadwood does not follow RFC2181's advice to ignore DNS responses with the TC (truncated) bit set, but instead extracts the first RR. If this is not desired, set the undocumented parameter truncation_hack to 0 (but read the DNS over TCP section of this man page).
Deadwood can not process DNS resource record types with numbers between 65392 and 65407. These RR types are marked by the IANA for "private use"; Deadwood reserves these record types for internal use. This is only 16 record types out of the 65536 possible DNS record types (only 71 have actually been assigned by IANA, so this is a non-issue in the real world).
In addition, Deadwood will, by default, respond to both ANY and HINFO requests with a RFC8482 compliant packet instead of trying to resolve the record.
It is not clear whether the DNS RFCs allow ASCII control characters in DNS names. Even if they were, Deadwood does not allow ASCII control characters (bytes with a value less then 32) in DNS names. Other characters (UTF-8, etc.) are allowed.
Combining a CNAME record with other records is prohibited in RFC1034 section 3.6.2 and RFC1912 section 2.4; it makes an answer ambiguous. Deadwood handles this ambiguity differently than some other DNS servers.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Sam Trenholme (http://www.samiam.org) is responsible for this program and man page. He appreciates all of Jean-Jacques Sarton's help giving this program IPv6 support.
askmara - do simple dns queries
askmara queries the user-specified dns server for records, and outputs the reply in a csv2-compatible format (csv2 is the format of zone files that maradns uses).
askmara [-n] [ -v | -t timeout] query [ server ]
-t
If this is present, the following argument is the askmara timeout,
in seconds. Note that askmara can not both have a user-defined
timeout and verbose output.
-v
If this is set, askmara will verbosely output the complete
reply that the server sent. Note that this verbose output is not
csv2-compatible.
-n
If this is set, askmara, when sending out a query, will not
request DNS recursion; in other words, askmara will request that the
remote DNS server not contact other DNS servers to answer the query in
question.
query
dns record to be queried. The query has two sections: The type
of record we desire, and the hostname we want this record for.
The type of query can have two forms: A one-letter mnemonic, or a numeric rtype followed by a colon. This is immediately concatenated by the full name of the host name we wish to look up.
For example, to ask for the IP of 'example.com.', we can use the one-letter mnemonic, in the form 'Aexample.com.', or we can use the numeric RR followed by a colon, giving the query '1:example.com.' (since A has the record type of one). Note that the query name needs the trailing dot at the end.
Askmara supports a handful one-letter mnemonics, as follows:
A signifies a request for an A (ipv4 address) RR
N signifies a NS RR
C signifies that we are asking for a CNAME RR
S signifies that we want a SOA RR
P signifies that we want a PTR RR
@ signifies that we mant a MX RR
T signifies that we want a TXT RR
Z signifies that we want to ask for all RRs.
server
IP address of the dns server to be queried. If no server is
given, askmara will query 127.0.0.1.
Asking the server with the ip 127.0.0.1 for the IP address of example.com:
askmara Aexample.com.
Asking the server with the ip 198.41.0.4 for the IP address of example.com:
askmara Aexample.com. 198.41.0.4
Asking the server with the ip address 127.0.0.1 for the IP address of example.com, using the rr_number:query format:
askmara 1:example.com.
Asking the server with the ip address 127.0.0.1 for a SRV record. In particular, we ask for the "http over tcp" service for example.net. Since askmara doesn't have a mnemonic for SRV record types, we use the numeric code (33 for SRV):
askmara 33:_http._tcp.example.net.
Asking the server with the ip address 127.0.0.1 for the AAAA (ipv6 ip) record for example.net:
askmara 28:example.net.
Note that the output will be a raw DNS packet in the SRV example, but askmara shows an IPv6 address (albeit without :: to collapse 0 quads) in the AAAA example.
When askmara is asked for an SOA record, the output of askmara closely resembles the format of a csv2 file, but can not be parsed as a csv2 file without modification.
askmara outputs multi-chunk ("character-string") TXT records incorrectly (it only outputs the first chunk).
maradns(8) http://www.maradns.org
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MaraDNS is written by Sam Trenholme. Jaakko Niemi used 5 minutes to roll this manpage together, which Sam has subsequently revised.
blockHashMake - Make a block hash file for Deadwood
blockHashMake is a stand alone command line tool which converts a list of host names in to a block hash file which Deadwood can read to block a large number of hosts quickly while using a minimum amount of memory to store the list of blocked hosts.
A block hash file uses a special binary format for storing a list of blocked host names.
blockHashMake reads the list of host names from the standard input and generates a binary file.
blockHashMake can be invoked without command line arguments. If invoked without arguments, blockHashMake reads the list of host names to block from standard input and outputs the block hash to a file name "bigBlock.bin"
blockHashMake can be invoked with a single "--help" or "--version" command line argument (e.g. "blockHashMake --version") which will output the version number of blockHashMake and provide basic usage information.
The command line arguments are as follows:
blockHashMake [filename] [sip hash key] [hash bucket count]
The filename is the name of the file we output the block hash to. If not specified, blockHashMake will output to the file named "bigBlock.bin". blockHashMake should not clobber an already existing file; if a file named "bigBlock.bin" (or the filename specified on the command line) already exists, be sure to delete the file before invoking blockHashMake to recreate the file.
The sip hash key is usually set by the blockHashMake program, which, by default, uses /dev/urandom to generate a random 64-bit key for the block hash file (the Windows port of blockHashMake uses the CryptGenRandom function to get a random 64-bit key). If the sip hash key is given a value of 0, this can make a block hash file which can be shared on the internet.
Warning: For security purposes, please set the sip hash key to 0 if sharing a block hash file on the internet!
Deadwood will only load a block hash file with a sip hash key of 0 if allow_block_hash_zero_key has a value of 1.
A user specified sip hash key only has up to 16 bits of entropy. sip hash key should not be used if a secret key for the hash compression algorithm is desired.
The hash bucket count is the number of hash buckets the resulting block hash file will have. Having more hash buckets makes the block hash file larger, but sometimes allows searching for a string in a block hash to be a little faster. The default value, which is 125% of the number of host names given to blockHashMake, is a reasonable compromise between speed and size.
After being invoked, blockHashMake reads a list of host names from the standard input. The format is a single host name per line of input, such as the following:
porn.example.com
naughty.foo
evil.host.invalid
Each line is a host name. Should there be a duplicate host name, blockHashMake will only store one instance of the host name in question. Host names are case insensitive; upper case ASCII letters are converted in to lower case letters beofre adding the host name to the block hash generated by blockHashMake.
blockHashMake has no support for Punycode. Please use another program to convert international domain names with non-ASCII characters in to their punycode representation before adding them to a block hash with blockHashMake.
The block hash format that blockHashMake uses is a 32-bit format, and the resulting block hash file should be under 2,147,483,648 bytes in size. This is a limitation of around 30 million host names.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This is a project developed on a strictly volunteer, non-commercial basis. It has been developed outside the course of a commercial activity, developed entirely in the Americas (i.e. outside of Europe) and therefore is not subject to the restrictions or conditions of the proposed EU Cyber Resilience Act. Someone selling a product that uses any component of this may be subject to this act and may need to handle any and all necessary compliance.
Sam Trenholme (https://www.samiam.org) is responsible for this program and man page.
blockHashRead - Read a block hash file
blockHashRead is a stand alone command line tool which converts a block hash file in to a list of hostnames. This way, a binary block hash file can be converted in to an ASCII list of host names, edited, and then converted back in to a binary block hash file with the blockHashMake utility.
A block hash file uses a special binary format for storing a list of blocked host names.
blockHashRead is invoked as follows:
blockHashRead --dump bigBlock.bin
Replace "bigBlock.bin" with the filename for the block hash file.
Doing this will output, on standard output, a list of host names in the block hash file. Each line will contain a single host name. When compiled for *NIX, the output will use *NIX line feeds; the Windows port of blockHashRead uses DOS line feeds.
blockHashRead can be invoked with a single "--help" or "--version" command line argument (e.g. "blockHashRead --version") which will output the version number of blockHashRead and provide basic usage information.
After being invoked, blockHashRead writes a list of host names to the standard output. The format is a single host name per line of input, such as the following:
porn.example.com
naughty.foo
evil.host.invalid
Each line is a host name.
blockHashRead has no support for Punycode. Please use another program to convert international domain names with non-ASCII characters in to their non-punycode representation if seeing correct international domain names is desired.
The block hash format that blockHashRead looks at is a 32-bit format, and the resulting block hash file should be under 2,147,483,648 bytes in size. This is a limitation of around 30 million host names.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This is a project developed on a strictly volunteer, non-commercial basis. It has been developed outside the course of a commercial activity, developed entirely in the Americas (i.e. outside of Europe) and therefore is not subject to the restrictions or conditions of the proposed EU Cyber Resilience Act. Someone selling a product that uses any component of this may be subject to this act and may need to handle any and all necessary compliance.
Sam Trenholme (https://www.samiam.org) is responsible for this program and man page.
coLunacyDNS - A DNS server configured by Lua
coLunacyDNS is a simply IPv4 and IPv6 forwarding DNS server (with support only for IPv4 and IPv6 IP records) controlled by a Lua script. It allows a lot of flexibility because it uses a combination of C for high performance and Lua for maximum control.
The current version of coLunacyDNS is version 1.0.011, made in January of 2021.
All example configuration files here are public domain.
On a CentOS 8 Linux system, this gets us started:
make
su
./coLunacyDNS -d
If one has clang
instead of GCC:
make CC="clang"
Here, we use coLunacyDNS.lua
as the configuration file.
Since coLunacyDNS runs on port 53, we need to start it as root. As soon as coLunacyDNS binds to port 53 and seeds its internal secure pseudo random number generator, it calls chroot and drops root privileges. It runs as the user and group with the user ID of 707; this value can be changed by altering UID and GID in the source code.
Cygwin users may use make -f Makefile.cygwin
(or, if one prefers,
make CFLAGS="-O3 -DCYGWIN"
also works) to compile coLunacyDNS, since
Cygwin does not have the same sandboxing Linux has. The Windows binary
does not have sandboxing, but other measures are taken to minimize
security risks.
In this example, we listen on 127.0.0.1, and, for any IPv4 query, we return the IP of that query as reported by 9.9.9.9.
bindIp = "127.0.0.1" -- We bind the server to the IP 127.0.0.1
function processQuery(Q) -- Called for every DNS query received
-- Connect to 9.9.9.9 for the query given to this routine
local t = coDNS.solve({name=Q.coQuery, type="A",
upstreamIp4="9.9.9.9"})
-- Return a "server fail" if we did not get an answer
if(t.error or t.status ~= 1) then return {co1Type = "serverFail"} end
-- Otherwise, return the answer
return {co1Type = "A", co1Data = t.answer}
end
As an even simpler example, we always return "10.1.1.1" for any DNS query given to us:
bindIp = "127.0.0.1" -- We bind the server to the IP 127.0.0.1
function processQuery(Q) -- Called for every DNS query received
return {co1Type = "A", co1Data = "10.1.1.1"}
end
We can also set the AA (authoritative answer) flag, the RA (recursion available) flag, and the TTL (time to live) for our answer. In this example, both the AA and RA flags are set, and the answer is given a time to live of one hour (3600 seconds).
bindIp = "127.0.0.1" -- We bind the server to the IP 127.0.0.1
function processQuery(Q) -- Called for every DNS query received
return {co1Type = "A", co1Data = "10.1.1.1",
co1AA = 1, co1RA = 1, co1TTL = 3600}
end
In this example, where we bind to both IPv4 and IPv6 localhost, we return 10.1.1.1 for all IPv4 A queries, 2001:db8:4d61:7261:444e:5300::1234 for all IPv6 AAAA queries, and "not there" for all other query types:
bindIp = "127.0.0.1" -- We bind the server to the IP 127.0.0.1
bindIp6 = "::1" -- Localhost for IPv6
function processQuery(Q) -- Called for every DNS query received
if Q.coQtype == 28 then
return {co1Type = "ip6",
co1Data="2001-0db8-4d61-7261 444e-5300-0000-1234"}
elseif Q.coQtype == 1 then
return {co1Type = "A", co1Data = "10.1.1.1"}
else
return {co1Type = "notThere"}
end
end
Note that coLunacyDNS always binds to an IPv4 address; if bindIp is not set, coLunacyDNS will bind to 0.0.0.0 (all available IPv4 addresses). In this example, we contact the DNS server 9.9.9.9 for IPv4 queries, and 149.112.112.112 for IPv6 queries:
bindIp = "127.0.0.1" -- We bind the server to the IP 127.0.0.1
bindIp6 = "::1" -- Localhost for IPv6
function processQuery(Q) -- Called for every DNS query received
local t
if Q.coQtype == 28 then -- Request for IPv6 IP
t = coDNS.solve({name=Q.coQuery,type="ip6",
upstreamIp4="149.112.112.112"})
elseif Q.coQtype == 1 then -- Request for IPv4 IP
t = coDNS.solve({name=Q.coQuery, type="A",
upstreamIp4="9.9.9.9"})
else
return {co1Type = "notThere"}
end
if t.error then
return {co1Type = "serverFail"}
end
if t.status == 28 then
return {co1Type = "ip6", co1Data = t.answer}
elseif t.status == 1 then
return {co1Type = "A", co1Data = t.answer}
else
return {co1Type = "notThere"}
end
end
Here is an example where we can synthesize any IP given to us:
-- This script takes a query like 10.1.2.3.ip4.internal. and returns the
-- corresponding IP (e.g. 10.1.2.3 here)
-- We use "internal" because this is the fourth-most commonly used
-- bogus TLD (#1 is "local", #2 is "home", and #3 is "dhcp")
-- Change this is a different top level domain as desired. So, if this
-- becomes "test", the this configuration script will resolve
-- "10.1.2.3.ip4.test." names to their IP.
TLD="internal"
-- Change these IPs to the actual IPs the DNS server will run on
bindIp = "127.0.0.1" -- We bind the server to the IP 127.0.0.1
bindIp6 = "::1" -- Localhost for IPv6
function processQuery(Q) -- Called for every DNS query received
if Q.coQtype == 1 then
local query = Q.coQuery
if query:match("^%d+%.%d+%.%d+%.%d+%.ip4%." .. TLD .. "%.$") then
local ip = query:gsub("%.ip4%." .. TLD .. "%.$","")
return {co1Type = "A", co1Data = ip}
end
else
return {co1Type = "notThere"}
end
return {co1Type = "notThere"}
end
Here is an example of using a block list to block bad domains.
The block list is stored in a file with a Deadwood compatible block
list; see the file make.blocklist.sh
in the upper level directory for
the tool used to make the file we read to find domains to block.
bindIp = "127.0.0.1" -- We bind the server to the IP 127.0.0.1
bindIp6 = "::1" -- Localhost for IPv6
-- Open up block list to know which domains to block
blockList = {}
if coDNS.open1("blocklist") then
line = coDNS.read1()
while line do
local name, seen = string.gsub(line,'^ip4%["([^"]+)".*$','%1')
if seen > 0 then
blockList[name] = "X"
end
line = coDNS.read1()
end
end
function processQuery(Q) -- Called for every DNS query received
local upstream = "9.9.9.9"
local t
-- Log query
coDNS.log("Got query for " .. Q.coQuery .. " from " ..
Q.coFromIP .. " type " .. Q.coFromIPtype)
-- Process blocklist
if blockList[Q.coQuery] == "X" then
coDNS.log("Name is on block list.")
return {co1Type = "notThere"}
end
if Q.coQtype ~= 1 and Q.coQtype ~= 28 then -- If not IPv4/6 query
return {co1Type = "notThere"} -- Send "not there" (like NXDOMAIN)
end
-- Look for the answer upstream
if Q.coQtype == 1 then
t = coDNS.solve({name=Q.coQuery, type="A", upstreamIp4=upstream})
else
t = coDNS.solve({name=Q.coQuery, type="ip6", upstreamIp4=upstream})
end
-- Handle errors; it is not possible to call coDNS.solve() again
-- in an invocation of processQuery if t.error is set.
if t.error then
coDNS.log(t.error)
return {co1Type = "serverFail"}
end
-- If we got an answer we can use, send it to them
if t.status > 0 and t.answer then
if t.status == 1 then
return {co1Type = "A", co1Data = t.answer}
elseif t.status == 28 then
return {co1Type = "ip6", co1Data = t.answer}
else -- Send notThere for unknown query type
return {co1Type = "notThere"}
end
end
coDNS.log("Unknown issue (or record not found)")
return {co1Type = "notThere"}
end
Here is a complex coLunacyDNS example, which uses a number of features:
-- coLunacyDNS configuration
bindIp = "127.0.0.1" -- We bind the server to the IP 127.0.0.1
-- Examples of three API calls we have: timestamp, rand32, and rand16
coDNS.log(string.format("Timestamp: %.1f",coDNS.timestamp()))
coDNS.log(string.format("Random32: %08x",coDNS.rand32()))
coDNS.log(string.format("Random16: %04x",coDNS.rand16()))
-- Note that it is *not* possible to use coDNS.solve here; if we attempt
-- to do so, we will get an error with the message
-- "attempt to yield across metamethod/C-call boundary".
function processQuery(Q) -- Called for every DNS query received
-- Because this code uses multiple co-routines, always use "local"
-- variables
local returnIP = nil
local upstream = "9.9.9.9"
-- Log query
coDNS.log("Got IPv4 query for " .. Q.coQuery .. " from " ..
Q.coFromIP .. " type " .. Q.coFromIPtype)
-- We will use 8.8.8.8 as the upstream server if query ends in ".tj"
if string.match(Q.coQuery,'%.tj%.$') then
upstream = "8.8.8.8"
end
-- We will use 4.2.2.1 as the upstream server if the query comes from
-- 192.168.99.X
if string.match(Q.coFromIP,'^192%.168%.99%.') then
upstream = "4.2.2.1"
end
if Q.coQtype ~= 1 then -- If it is not an A (ipv4) query
-- return {co1Type = "ignoreMe"} -- Ignore the query
return {co1Type = "notThere"} -- Send "not there" (like NXDOMAIN)
end
-- Contact another DNS server to get our answer
local t=coDNS.solve({name=Q.coQuery, type="A", upstreamIp4=upstream})
-- If coDNS.solve returns an error, the entire processQuery routine is
-- "on probation" and unable to run coDNS.solve() again (if an attempt
-- is made, the thread will be aborted and no DNS response sent
-- downstream).
if t.error then
coDNS.log(t.error)
return {co1Type = "serverFail"}
end
-- Status being 0 means we did not get an answer from upstream
if t.status ~= 0 and t.answer then
returnIP = t.answer
end
if string.match(Q.coQuery,'%.invalid%.$') then
-- Answer for anything.invalid
return {co1Type = "A", co1Data = "10.1.1.1"}
end
if returnIP then
return {co1Type = "A", co1Data = returnIP}
end
return {co1Type = "notThere"}
end
Since the Lua file is executed as root, some effort is made to restrict what it can do:
-
Only the math, string, and bit32 libraries are loaded from Lua's standard libs. (bit32 actually is another Bit library, but with a bit32 interface.)
-
A special coDNS library is also loaded.
-
The program is designed to give Lua very limted access to the filesystem nor be able to do anything malicious.
-
coDNS.open1() can only open a file in the directory coLunacyDNS is called from; it can not open files in other directories.
-
All DNS ANY and HINFO queries are given a RFC8482 response.
coLunacyDNS only processes requests for DNS A queries and DNS AAAA queries -- queries for IPv4 and IPv6 IP addresses. Information about other query types is not available to coLunacyDNS, and it can only return A queries, AAAA queries, “server fail”, or “this name is not here” in its replies.
coLunacyDNS, likewise, can only send A (IPv4 IP) and AAAA (IPv6 IP) requests to upstream servers. While coLunacyDNS can process and forward IPv6 DNS records, and while coLunacyDNS can bind to IPv4 and IPv6 IPs, it can not send queries to upstream DNS servers via IPv6, and coLunacyDNS must always have an IPv4 address to bind to.
coLunacyDNS, when running Lua code, has access to the Lua 5.1 versions of the math and string libraries. The math library has the functions math.abs, math.acos, math.asin, math.atan, math.atan2, math.ceil, math.cos, math.cosh, math.deg, math.exp, math.floor, math.fmod, math.frexp, math.huge, math.ldexp, math.log, math.log10, math.max, math.min, math.modf, math.pi, math.pow, math.rad, math.random, math.randomseed, math.sin, math.sinh, math.sqrt, math.tan, and math.tanh. Almost all of them are the same as they are in Lua 5.1; the only one which is different is math.random, which uses RadioGatun[32] instead of rand to generate random numbers, math.randomseed, which takes a string as the random seed (if a number is given, Lua uses coercion to convert the number in to a string), and math.rand16() (not available in stock Lua) which returns a 16-bit random integer between 0 and 65535.
coLunacyDNS also has access to the string library: string.byte, string.char, string.dump, string.find, string.format, string.gmatch, string.gsub, string.len, string.lower, string.match, string.rep, string.reverse, string.sub, and string.upper. All of these are as per Lua 5.1.
string.match(str, pattern), for example, looks for the regular expression pattern in the string `str; regular expression are non-Perl compatible Lua regular expressions. There are number of changes; one being that, instead of using a backslash to escape characters, Lua regular expressions use % (so "%." matches against a literal dot, while "." matches against any character).
While Lua 5.1 does not include the bit32 library, coLunacyDNS uses a bit manipulation library with an interface like bit32: The numbers are 32-bit numbers, and the function calls are bit32.arshift, bit32.band, bit32.bnot, bit32.bor, bit32.bxor, bit32.lshift, bit32.rshift, and bit32.rrotate.
coLunacyDNS also includes a few functions in its own coDNS space:
-
coDNS.log This takes a single string as its input, and logs the string in question. The logging method depends on the OS being used: In Windows it writes to a log file; in *NIX it currently outputs the message on standard output. If logLevel is 0, its output on *NIX is buffered; if logLevel is 1 or higher, its output is flushed after every call to coDNS.log.
-
coDNS.timestamp This returns coLunacyDNS's internal time representation. This is not a standard *NIX timestamp; instead it's a special timestamp generated by coLunacyDNS in a Y2038-compliant manner (in places where time_t is 32-bit and we do not have an alternate API to get numbers, we assume negative timestamps are in the future; on Windows 32-bit, we use the Y2038 compatible 64-bit Windows NT fileTime timestamps; and on places with a 64-bit time_t, we consider the timestamp accurate and merely convert it). Each second has 256 ticks.
-
coDNS.rand32 This returns a random integer between 0 and 4294967295.
-
coDNS.rand16 This returns a random integer between 0 and 65535.
-
coDNS.solve This function, which can only be called inside of processQuery, requests a DNS record from another DNS server, and returns once the data is available (or if the DNS server does not respond, or if it gives us a reply that we did not get a record). This function is described in more detail in the following section.
-
coDNS.open1, coDNS.read1, and coDNS.close1 can be used to read a text file in the same directory that coLunacyDNS is being run from. Details are below, after the coDNS.solve section.
This function is given a table with three members:
-
name, which is the DNS name in human format like example.com. The final dot is mandatory
-
type, which can be A (IPv4) or ip6 (IPv6)
-
upstreamIp4, which is the IP connect to; this is a string in IPv4 dotted decimal format, like 10.1.2.3 or 9.9.9.9. If upstreamIp4 is not present, coLunacyDNS looks for a global variable called upstreamIp4 to see if a default value is available.
It outputs a table with a number of possible elements:
-
error: If this is in the return table, an error happened which makes it not possible to have coDNS.solve run. Errors include giving coDNS.solve a bad query for its DNS name; not giving coDNS.solve a table when calling it; not having the element type in the table given to coDNS.solve; etc. Once an error is returned, it is not possible to run coDNS.solve again in the current thread; if one calls coDNS.solve a second time after getting an error, the thread will be terminated and the client will not receive a DNS reply.
-
status: If we got an IPv4 address from the upstream server, this returns the number 1. If we got an IPv6 address from the upstream server, this returns the number 28 (the DNS number for an IPv6 reply). Otherwise, this returns the number 0.
-
answer: This is the answer we got from the upstream DNS server. If the answer is an IPv4 IP, the answer is a string with a standard dotted decimal IP in it, such as 10.4.5.6. If the answer is an IPv6 IP, the answer is a string with the IPv6 IP in it, in the form XXXX-XXXX-XXXX-XXXX XXXX-XXXX-XXXX-XXXX, where each X is a hexadecimal digit, such as 2001-0db8-4d61-7261 444e-5300-0000-0001 All 32 hexadecimal digits that comprise an IPv6 address will be present in the reply string. Should there be a timeout or error getting an answer from the upstream DNS server, this string will have the value DNS connect error. Should we get a reply from the upstream DNS server, but an answer was not seen (usually, because we asked for a DNS record which does not exist), the answer field will have the string DNS answer not seen.
-
rawpacket: If the global variable logLevel has a value of 0, this will always be nil. If logLevel is 1, this will be nil if we were able to extract an answer from the upstream DNS server; otherwise, this will be an escaped form of the raw packet sent to us from upstream. If logLevel is 2 or higher, this will always be an escaped raw packet from upstream. In an escaped packet, characters which are between ASCII 0 and z will be shown as is; otherwise, they will be in the form {1f}, where the hex value of the byte is shown between the brackets ({ and } have an ASCII value above z).
Since this function allows other Lua threads to run while it awaits a DNS reply, global variables may change in value while the DNS record is being fetched.
We have an API which can be used to read files. For example:
if not coDNS.open1("filename.txt") then
return {co1Type = "serverFail"}
end
local line = ""
while line do
if line then coDNS.log("Line: " .. line) end
line = coDNS.read1()
end
The calls are: coDNS.open1(filename), coDNS.read1(), and coDNS.close1().
Only a single file can be open at a time. If coDNS.open1() is called when a file is open, the currently open file is closed before we attempt to open the new file. If coDNS.solve() is called while a file is open, the file is closed before we attempt to solve the DNS query. If we exit processQuery() while a file is open, the file is closed as we exit the function. Files are also closed when we finish parsing the Lua configuration file used by coLunacyDNS, before listening to DNS queries.
The filename must start with an ASCII letter, number, or the _ (underscore) character. The filename may contain only ASCII letters, numbers, instances of . (the dot character), or the _ character. In particular, the filename may not contain /, , or any other commonly used directory separator.
If the file is not present, or the filename contains an illegal character, or the file can not be opened, coDNS.open1 will return a false boolean value. Otherwise, open1 returns the true boolean.
The file has to be in the same directory that coLunacyDNS is run from. The file may only be read; writing to the file is not possible.
coDNS.read1() reads a single line from the file. Any newline is stripped from the end (unlike Perl, coLunacyDNS does not require a chop); NUL characters in the line also truncate the string read. If a line is read from the file, coDNS.read1() returns the line which was read. Otherwise, coDNS.read1() returns the false Lua boolean value.
coDNS.read1() assumes that a single line will be under 500 bytes in size. Behavior is undefined when trying to read a longer line.
coDNS.close1() closes an open file; a file is also closed when opening another file, ending processQuery(), or calling coDNS.solve(). It is mainly here to give programmers trained to close open files a function which does so.
Every time coLunacyDNS gets a query, it runs the lua function processQuery, which takes as its input a table with the following members:
-
coQuery: This is the DNS name requested, in the form of a string like caulixtla.com. or samiam.org. (observe the dot at the end of the coQuery string). If the string has anything besides an ASCII letter, an ASCII number, the - character (dash), or the _ character (underline), the character will be a two-digit hexadecimal number in brackets. If we get the raw UTF-8 query ñ.samiam.org (where the first character is a n with a tilde), coQuery will look like {c3}{b1}.samiam.org.
-
coQtype: The is the numeric DNS query type requested. This is a number between 0 and 65535, and corresponds to the DNS query type made. A list of DNS query type numbers is available at https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml 1 is "A", i.e. a request for an IPv4 IP address.
-
coFromIP: This is a string containing, in human-readable format, the IP the query came from. The string will look like 10.9.8.7.
-
coFromIPtype: This is the string IPv4
The processQuery function returns as its output a table with the following parameters:
-
co1Type: This is a string which can have the following values: "ignoreMe" (no DNS reply will be sent back to the client), "notThere" (tell the client that this DNS name does not exist for the query type requested), "serverFail" (send a "server fail" to the client), "A" (send an IPv4 IP answer back to the client), or "ip6" (send an IPv6 IP answer back to the client). Please note that "ignoreMe" does not guarantee that coLunacyDNS ignores all DNS queries; coLunacyDNS will always respond to ANY or HINFO queries in a RFC8482 manner; if one wishes to drop all DNS packets, this can be done at the firewall level. This field is mandatory.
-
co1Data: This is to be a string. When co1Type is "A", this is an IPv4 IP in dotted decimal format, e.g. 10.1.2.3. When co1type is "ip6", and co1data is either a standard IPv6 string, such as "2001:db8:1234::5678", or a string with 32 hexadecimal digits, the IPv6 IP in the string is returned to the client. If the character _ is in the ip6 string and the character : is not present in the string, this is treated as if it were the number 0; the characters " " (space) and - (dash) are ignored. For example, both "2001:db8::8" and "2001-0db8-4d61-7261 444e-5300-0000-__01" (without linefeed) are allowed values for co1data when co1type is "ip6". This field is mandatory when co1type is "A" or "ip6".
-
co1AA: This field, when set with the numeric value of 1, gives the AA flag in the DNS reply a value of true; in other words, the DNS answer is marked as “authoritative”. This field is optional; if not set, the reply is not marked authoritative.
-
co1RA: This field, when set with the numeric value of 1, gives the RA flag in the DNS reply a value of true, indicating that the coLunacyDNS server can process recursive queries. This field is optional; if not set, the reply is not marked as having recursion available.
-
co1TTL: This numeric field, if set, determines the DNS TTL (suggested time to live for the record) of the reply. This is the TTL in raw seconds, and can have a value between 0 (do not cache) and 7777777 (cache for just over 90 days). This field is optional; if not set, the TTL returned will be 0 (do not cache).
coLunacyDNS Lua scripts have three special global variables which are read to adjust settings in coLunacyDNS:
-
bindIp: This is the IPv4 IP that coLunacyDNS will use as a DNS server. If this is not set, then coLunacyDNS will bind to the IP 0.0.0.0 (all IP addresses the machine running coLunacyDNS has)
-
bindIp6: This is the IPv6 IP that coLunacyDNS will bind to. If this is not set, coLunacyDNS will only bind to IPv4. The IP address is in standard IPv6 format, e.g. "2001:0db8:f00:ba4::2020" or in MaraDNS-specific format, e.g. "2001-0db8-0f00-0ba4 00__00__00__2020"
-
logLevel: If this is set, more information will be logged and passed to Lua scripts which can be used for debugging purposes. This can have a value between 0 and 10; higher values result in more logging. If logLevel has a value of 0, log messages generated with coDNS.log are buffered and will not immediately be visible; if logLevel has a value more than 0,
coDNS.log
messages are immediately flushed (unbuffered).
coLunacyDNS is feature complete and stable.
coLunacyDNS is a stable and fully tested DNS server. Test coverage is at or very near 100%
Note: Some blocks of code, sanity tests to make sure we’re not in a
corner case which can not be readily replicated, have been removed from
the testing code via #ifdef
. Read sqa/README.md for details.
csv1 - Format of the csv1 zone file that MaraDNS uses
The csv1 zone file format is supported primarily for MaraDNS users who already have zone files in the csv1 format. MaraDNS now supports a csv2 zone file format. Note that the csv1 zone file format will continue to function as long as I am MaraDNS' maintainer.
|
This delimits fields
#
This signifies a comment. Lines starting with this are ignored,
otherwise it has no significance
%
This, in domain names, signifies that the rest of the domain name
should be the name of this zone
*
This is translated to mean "any host name that otherwise does not
resolve". It must be at the beginning of a domain name.
\
This is used as an escape character, either to escape octal values
such as '\045' for %, or to escape the '%' character so it has no
special meaning, or to escape the backslash character.
All domain-name labels are converted to their lower-case equivalents before processing is done. This is because domain-name literals in the database with one or more upper-case letters in them are case-sensitive. This is my way to resolve RFC1035's desire to both allow binary domain labels and be case-insensitive.
The file must first have a SOA record, followed by one or more NS records, followed by other records. The initial NS and SOA records must be RR for this zone. NS records after any non-NS record must be part of another zone. The resolution algorithm will not break if non-CNAME records share records with a CNAME record, but this is not a good idea to do.
A domain name is a one-letter designation of its type, followed by the domain name separated by dots, ending with either a % or a trailing dot. If the domain name does not end with a % or trailing dot, an error is returned.
MaraDNS only supports the following types of resource records (RRs) in csv1 files. More resource records types are supported in csv2 zone files; see csv2(5) for details.
Letter Type RFC1035 section 3.2.2 value
A A 1
N NS 2
C CNAME 5
S SOA 6
P PTR 12
@ MX 15
T TXT 16
U any determined in third field of line
Here are the formats, shown by letter name:
A: Has three fields
field one: the domain name
field two: the ttl for the name in seconds
field three: the ip address, in dotted decimal notation
Example:
Ahost.example.com.|7200|10.1.2.3
A records are described with grueling detail in RFC1035. In short, an A record is an IP address for a given host name.
N: Has three fields
field one: the domain name of the record
field two: the ttl for the name in seconds
field three: the domain name this NS points to.
Example:
Nexample.com.|86400|ns.example.com.
NS (N here) records are described in RFC1035
C: Has three fields
field one: the domain name of the record
field two: the ttl for the name in seconds
field three: the domain this CNAME record points to
Example:
Calias.example.org.|3200|realname.example.org.
CNAME (which C is short for) records are described in RFC1035
S: Has nine fields
field one: the domain name of the record
field two: the TTL of the record
field three: the origin of the domain. In other words, the name of the
primary name server for the domain.
field four: the email address for this domain (in the RFC822, not
BIND format)
field five: the serial for the domain
field six: the refresh (how often to see updates) for the domain
field seven: the retry (how often to try when down) for the domain
field eight: the expire (how long before the slave gives up) for the
domain
field nine: the minimum (and default) TTL for the domain
Example:
Sexample.net.|86400|%|hostmaster@%|19771108|7200|3600|604800|1800
SOA (S here) records are described in RFC1035
P: has three fields
field one: the IP we wish to point to (in in-addr.arpa form)
field two: the ttl for the name in seconds
field three: the FQDN for the IP in question
Example:
P3.2.1.10.in-addr.arpa.|86400|ns.example.com.
PTR (P here) records, which are used for reverse DNS lookups, are described in RFC1035. Note that one needs control of the appropriate in-addr.arpa subdomain to make PTR records visible on the internet at large.
@: has four fields
field one: The host that people send email to
field two: the ttl for this record
field three: The preference for this MX host
field four: The name of this MX host
Example:
@example.com.|86400|10|mail.example.com.
MX (@ here) records are described in RFC1035
T: has three fields
field one: The host someone wants to get additional information about
field two: the ttl for this record
field three: The desired text. Any data becomes the record up until a
new line is reached. The new line is not part of the TXT
record
Example:
Texample.com.|86400|Example.com: Buy example products online
TXT (T here) records are described in RFC1035
U: has four fields
field one: The host someone wants a data type normally unsupported by
MaraDNS for
field two: the ttl for this record
field three: The numeric code for this data type (33 for SRV, etc.)
field four: The raw binary data for this data type
Example:
Uexample.com.|3600|40|\010\001\002Kitchen sink data
The above example is a "Kitchen Sink" RR (see draft-ietf-dnsind-kitchen-sink-02.txt) with a "meaning" of 8, a "coding" of 1, a "subcoding" of 2, and a data string of "Kitchen sink data". Since this particular data type is not formalized in a RFC at this time, the most appropriate method of storing this data is by using the catch-all "unsupported" syntax.
# Example CSV1 zone file
# This is what is known as a SOA record. All zone files need to have one
# of these
S%|86400|%|hostmaster@%|19771108|7200|3600|604800|1800
# These are known as authoritative NS records. All zone files need one or
# more of these
N%|86400|ns1.%
N%|86400|ns2.%
# Some IP addresses
Ans1.%|86400|10.0.0.1
Ans2.%|86400|192.168.0.1
A%|86400|10.1.2.3
Amx.%|86400|10.1.2.4
# An 'IN MX' record
@%|86400|10|mx.%
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Sam Trenholme http://www.samiam.org/
csv2 - Description of the csv2 zone file that MaraDNS uses
The csv2 zone file format is MaraDNS' standard zone file format. This zone file format uses any kind of whitespace (space, tab, and carriage return), or the '|' character, to delimit fields.
In newer MaraDNS releases, the tilde ('~') character is used to delimit records in csv2 zone files; in order to maintain maximum compatibility with older MaraDNS zone files, this feature is only enabled if a tilde is placed between the first and second record. Otherwise, tildes are not allowed in zone files (except in comments).
Most older MaraDNS csv2 zone files without the tilde character are compatible with the updated csv2 parser, unless csv2_tilde_handling is set to 3. All older MaraDNS csv2 zone files will parse in MaraDNS if csv2_tilde_handling has a value of 0. Older MaraDNS releases also supported the csv2_tilde_handling variable (as long as it had a value of 0); this allowed the same configuration and zone files to be used in older and newer MaraDNS releases.
This zone file format has records in the following form:
name [+ttl] [rtype] rdata ~
The name is the name of the record we will add, such as "www.example.net.". This must be placed at the beginning of a line. The rtype is the record type for the record, such as "A" (ipv4 IP address), "MX" (mail exchanger), or "AAAA" (ipv6 IP address). The ttl is how long other DNS servers should store this data in their memory (in seconds); this field needs a '+' as its initial character. The rdata is the actual data for this record; the format for the rdata is type-specific.
Anything in square brackets is an optional field. If the ttl is not specified, the ttl is set to the default ttl value (see "Default TTL" below). If the rtype is not specified, it is set to be an "A" (ipv4 address) record.
The zone file supports comments; comments are specified by having a '#' anywhere between fields or records; when a '#' is seen, the csv2 parser ignores any character it sees (with the exception of the '{', which is not allowed in comments) until a newline. A '#' can usually be placed inside a field, and indicates the end of a field when placed there.
A '{' character can never be placed in a comment. A '~' character is always allowed in a comment, and has no special meaning when placed in a comment.
The following record types are supported; a description of the record data format accommodates the record type:
An A record stores an ipv4 address. This is the default record type should the record type not be specified. The record type has one field in it: the IP for the record. Examples:
a.example.net. 10.11.12.13 ~
b.example.net. A 10.11.12.14 ~
c.example.net. +64000 A 10.11.12.15 ~
A PTR record stores the name for a given ipv4 or ipv6 address, and is used for reverse DNS lookups. This record type has one field in it: The name for the record in question. Examples:
13.12.11.10.in-addr.arpa. PTR a.example.net. ~
14.12.11.10.in-addr.arpa. PTR b.example.net. ~
15.12.11.10.in-addr.arpa. +64000 PTR c.example.net. ~
A MX record stores a mail exchange record, and is used for mail delivery. This record type has two fields in it: The priority (or "preference" in traditional DNS parlance) of the MX record (lower numbers get higher priority), and the name of the mail exchanger. Example of mail for example.net being mailed to mail.example.net, which has the IP "10.11.12.16":
example.net. MX 10 mail.example.net. ~
mail.example.net. 10.11.12.16 ~
An AAAA record stores the ipv6 address for a given name. The IP is in standard ipv6 "colon delimited" format: eight 16-bit hexadecimal numbers are separated by colons. Two colons together indicate multiple streams of all-zero hex numbers. This record has only one field, the v6 IP. Example:
a.example.net. AAAA 2001:db8:dec:ade::f ~
An SRV record stores a "service" definition. This record has four fields: Priority, weight, port, and target. For more information, please refer to RFC 2782. Example:
_http._tcp.% SRV 0 0 80 a.% ~
A NAPTR record is described in RFC 2915. Example:
www.example.com. NAPTR 100 100 's';'http+I2R';'' _http._tcp.example.com. ~
Note the semicolons. Because of a bug in MaraDNS 1.4.03 and earlier releases, NAPTR records will not parse unless a ~ is not used to separate records; a patch to fix this bug is available here.
An NS record specifies the name servers for a given zone. If the name servers are not delegation name servers (in other words, if the name servers are the authoritative name servers for the zone), they need to be at the beginning of the zone, either as the first records in the zone, or right after the SOA record. The NS records are optional; if not present, MaraDNS will make an educated guess of that NS records should be there, based on the IPs the MaraDNS process is bound to. This record has one field: The name of the name server machine. Example:
example.net. NS ns1.example.net. ~
example.net. NS ns2.example.net. ~
An SOA record stores the start of authority for a given zone file. This record is optional in a CSV2 zone file; should the record not be in the zone file, MaraDNS will synthesize an appropriate SOA record. This record can only exist once in a zone file: As the first record of the zone file. This record has seven fields: The name of the zone, the email address of the person responsible for the zone, and five numeric fields (serial, refresh, retry, expire, and minimum). Note that the SOA minimum does not affect other TTLs in MaraDNS. Example:
x.org. SOA x.org. [email protected]. 1 7200 3600 604800 1800 ~
If there is a '.' (dot) character in the part of the email address before the '@', it needs to be escaped thusly:
x.org. SOA x.org. john\[email protected]. 1 7200 3600 604800 1800 ~
Note that the csv2 parser will not allow more than one dot in a row; '[email protected]' will cause a parse error. In addition, the dot character must be escaped with a backslash.
The serial numeric field may be replaced by the string '/serial'; this string tells the CSV2 zone parser to synthesize a serial number for the zone based on the timestamp for the zone file. This allows one to have the serial number be automatically updated whenever the zone file is edited. Here is how this special field looks in a SOA record:
x.org. SOA x.org. [email protected]. /serial 7200 3600 604800 1800 ~
The '/serial' string is case-sensitive; only '/serial' in all lower case will parse.
A TXT record stores arbitrary text and/or binary data for a given host name. This record has one field: The text data for the record.
A basic text record can be stored by placing ASCII data between two single quotes, as follows:
example.com. TXT 'This is an example text field' ~
Any binary data can be specified; see the csv2_txt(5) manual page for full details.
If tildes are used to separate records, a TXT record can not contain a literal '|' (pipe) character, a '#' literal, a '~' literal, nor any ASCII control literal; these characters can be added to a TXT record via the use of escape sequences; read the csv2_txt man pagefor details.
A SPF record is, with the exception of the numeric rtype, identical to a TXT record. SPF records are designed to make it more difficult to forge email.
Here is one example SPF record:
example.com. SPF 'v=spf1 +mx a:colo.example.com/28 -all' ~
Use '\x7e' to put a tilde ("~" character) in a SPF record:
example.com. SPF 'v=spf1 +mx a:colo.example.com/28 '\x7e'all' ~
More information about SPF records can be found in RFC4408, or by performing a web search for 'sender policy framework'.
Note that SPF records never gained traction, and their role is handled by TXT records.
The RAW record is a special meta-record that allows any otherwise unsupported record type to be stored in a csv2 zone file. The syntax is:
RAW [numeric rtype] [data] ~
The numeric rtype is a decimal number.
The data field can, among other thing, have backslashed hex sequences outside of quotes, concatenated by ASCII data inside quotes, such as the following example:
example.com. RAW 40 \x10\x01\x02'Kitchen sink'\x40' data' ~
The above example is a "Kitchen Sink" RR with a "meaning" of 16, a "coding" of 1, a "subcoding" of 2, and a data string of "Kitchen sink@ data" (since hex code 40 corresponds to a @ in ASCII). Note that unquoted hex sequences are concatenated with quoted ASCII data, and that spaces are only inside quoted data.
The format for a data field in a RAW record is almost identical to the format for a TXT data field. Both formats are described in full in the csv2_txt(5) manual page.
The FQDN4 (short for "Fully Qualified Domain Name for IPv4") record is a special form of the "A" record (see above) that instructs MaraDNS to automatically create the corresponding PTR record. For example, the following is one way of setting up the reverse DNS lookup for x.example.net:
x.example.net. A 10.3.28.79 ~
79.28.3.10.in-addr.arpa. PTR x.example.net. ~
But the above two lines in a zone file can also be represented thusly:
x.example.net. FQDN4 10.3.28.79 ~
Note that the csv2 parser does not bother to check that any given IP only has a single FQDN4 record; it is up to the DNS administrator to ensure that a given IP has only one FQDN4 record. In the case of there being multiple FQDN4 records with the same IP, MaraDNS will have multiple entries in the corresponding PTR record, which is usually not the desired behavior.
FQDN4 records are not permitted in a csv2_default_zonefile. If you do not know what a csv2_default_zonefile is, you do not have to worry about this limitation.
The FQDN6 (short for "Fully Qualified Domain Name for IPv6") record is the ipv6 form for the FQDN4 record. Like the FQDN4 record, this record creates both a "forward" and "reverse" DNS record for a given host name. For example, one may have:
x.example.net. AAAA 2001:db8:dec:ade::b:c:d ~
d.0.0.0.c.0.0.0.b.0.0.0.0.0.0.0.e.d.a.0.c.e.d.0.8.b.d.0.1.0.0.2 PTR
x.example.net. ~
But the above two lines in a zone file can also be represented thusly:
x.example.net. FQDN6 2001:db8:dec:ade::b:c:d ~
Like FQDN4 records, it is the DNS administrator's duty to make sure only a single IP has a FQDN6 record.
FQDN6 records are, like FQDN4 records, not permitted in a csv2_default_zonefile. If you do not know what a csv2_default_zonefile is, you do not have to worry about this limitation.
FQDN6 records were implemented by Jean-Jacques Sarton.
A CNAME record is a pointer to another host name. The CNAME record, in MaraDNS, affects any record type not already specified for a given host name. While MaraDNS allows CNAME and non-CNAME records to share the same host name, this is considered bad practice and is not compatible with some other DNS servers.
CNAME records are not permitted in a csv2_default_zonefile. If you do not know what a csv2_default_zonefile is, this fact is of no relevance.
The following resource records are mainly of historical interest, or are not commonly used.
In light of RFC8482, using this record type is strongly discouraged.
An HINFO record is a description of the CPU (processor) and OS that a given host is using. The format for this record is identical to a TXT record, except that the field must have precisely two chunks.
The first chunk of a HINFO record is the CPU the host is running; the second chunk is the OS the host is running.
Example:
example.com. HINFO 'Intel Pentium III';'CentOS Linux 3.7' ~
This resource record is not actively used--the IANA has a list of CPUs and OSes that this record is supposed to have. However, this list has not been updated since 2002.
Since MaraDNS has support for RFC8482, ANY queries sent to MaraDNS will return an HINFO record with a CPU of "RFC8482" and a blank OS name.
WKS records are historical records which have been superseded by SRV records. The format of the record is an IP, followed by a protocol number (6 means TCP), followed by a list of ports that a given server has available for services.
For example, to advertise that example.net has the IP 10.1.2.3, and has a SSH, HTTP (web), and NNTP server:
example.net. WKS 10.1.2.3 6 22,80,119 ~
MaraDNS only allows up to 10 different port numbers in a WKS record, and requires that the listed port numbers not be higher than 1023.
MD and MF records are RR types that existed before MX records, and were made obsolete by MX records. RFC1035 says that a DNS server can either reject these records or convert these records in to MX records. BIND rejects these records; MaraDNS converts them.
Example:
example.net. MD a.example.net. ~
example.net. MF b.example.net. ~
Is equivalent to:
example.net. MX 0 a.example.net. ~
example.net. MX 10 b.example.net. ~
In the late 1980s, an alternative to MX records was proposed. This alternative utilized MB, MG, MINFO, and MR records. This alternative failed to gather popularity. However, these records were codified in RFC1035, and are supported by MaraDNS. Here is what the records look like:
example.net. MB mail.example.net. ~
example.net. MG [email protected]. ~
example.net. MINFO [email protected]. [email protected]. ~
example.net. MR [email protected]. ~
More information about these records can be found in RFC1035.
AFSDB, RP, X25, ISDN, and RT are resource records which were proposed in RFC1183. None of these resource records are widely used.
With the exception of the ISDN record, the format of these records is identical to the examples in RFC1183. The format of the ISDN record is identical unless the record has a subaddress (SA). If an ISDN record has a subaddress, it is separated from the ISDN-address by a ';' instead of whitespace.
If used, here is how the records would look in a csv2 zone file:
example.net. AFSDB 1 afsdb.example.net. ~
example.net. RP [email protected]. rp.example.net. ~
example.net. RP [email protected]. . ~
example.net. X25 311061700956 ~
example.net. ISDN 150862028003217 ~
example.net. ISDN 150862028003217;004 ~
example.net. RT 10 relay.example.net. ~
NSAP and NSAP-PTR records were proposed in RFC1706. A NSAP record is a hexadecimal number preceded by the string "0x" and with optional dots between bytes. This hexadecimal number is converted in to a binary number by MaraDNS. A NSAP-PTR record is identical to a PTR record, but has a different RTYPE.
More information about these records can be obtained from RFC1706.
If used, here is how the records would look in a csv2 zone file:
example.net. NSAP 0x47.0005.80.005a00.0000.0001.e133.ffffff000162.00 ~
example.net. NSAP-PTR nsap.example.net. ~
The PX RR is an obscure RR described in RFC2163. A PX record looks like this in a CSV2 zone file:
example.net. PX 15 px1.example.net. px2.example.net. ~
An GPOS record is a description of the location of a given server. The format for this record is identical to a TXT record, except that the field must have precisely three chunks.
The first chunk of a GPOS record is the longitude; the second chunk is the latitude; the third chunk is the altitude (in meters).
Example:
example.net. GPOS '-98.6502';'19.283';'2134' ~
More information about this record can be found in RFC1712.
This resource record is not actively used; for the relatively few people who encode their position in DNS, the LOC record is far more common.
The LOC resource record is an uncommonly used resource record that describes the position of a given server. LOC records are described in RFC1876.
Note that MaraDNS' LOC parser assumes that the altitude, size, horizontal, and vertical precision numbers are always expressed in meters. Also note that that sub-meter values for size, horizontal, and vertical precision are not allowed. Additionally, the altitude can not be greater than 21374836.47 meters.
Example:
example.net. LOC 19 31 2.123 N 98 3 4 W 2000m 2m 4m 567m ~
MaraDNS does not have direct support for CAA records. However, the RAW record type can generate CAA records. For example, to have "example.com" have a CAA record with the value of "issue letsencrypt.org":
example.com. RAW 257 \x00\x05'issueletsencrypt.org' ~
MaraDNS has support for star records in zone files:
*.example.net. A 10.11.12.13 ~
In this example, anything.example.net will have the IP 10.11.12.13. Note that this does not set the ip for "example.net", which needs a separate record:
example.net. A 10.11.12.13 ~
Note also that stars must be at the beginining of a name; to have stars at the end of a name, use the csv2_default_zonefile feature as described in the mararc man page.
Placing the percent symbol at the end of a record indicates that the percent should be replaced with the domain name for the zone.
For example, in the zone for example.net. (e.g. one's mararc file has csv2["example.net."] = "db.example.net", and we are editing the "db.example.net" file):
www.% A 10.10.10.10 ~
This will cause "www.example.net" to have the ip 10.10.10.10.
In addition to being able to have resource records and comments, csv2 zone files can also have special slash commands. These slash commands, with the exception of the '/serial' slash command (see "SOA" above), can only be placed where the name for a record would be placed. Like resource records, a tilde is to be placed after the slash command. Note also that slash commands are case-sensitive, and the command in question must be in all-lower-case.
These commands are as follows:
The default TTL is the TTL for a resource record without a TTL specified. This can be changed with the '/ttl' slash command. This command takes only a single argument: The time, in seconds, for the new default TTL. The '/ttl' slash command only affects the TTL of records that follow the command. A zone file can have multiple '/ttl' slash commands.
The default TTL is 86400 seconds (one day) until changed by the '/ttl' slash command.
In the following example, a.ttl.example.com will have a TTL of 86400 seconds (as long as the zone file with this record has not previously used the '/ttl' slash command), b.ttl.example.com and d.ttl.example.com will have a TTL of 3600 seconds, c.ttl.example.com will have a TTL of 9600 seconds, and e.ttl.example.com will have a TTL of 7200 seconds:
a.ttl.example.com. 10.0.0.1 ~
/ttl 3600 ~
b.ttl.example.com. 10.0.0.2 ~
c.ttl.example.com. +9600 10.0.0.3 ~
d.ttl.example.com. 10.0.0.4 ~
/ttl 7200 ~
e.ttl.example.com. 10.0.0.5 ~
It is possible to change the host name suffix that is used to substitute the percent in a csv2 zone file. This suffix is called, for historical and compatibility reasons, "origin". This is done as the slash command '/origin', taking the new origin as the one argument to this function. Note that changing the origin does not change the domain suffix used to determine whether a given domain name is authoritative.
Here is one example usage of the '/origin' slash command:
/origin example.com. ~
www.% 10.1.0.1 ~
% MX 10 mail.% ~
mail.% 10.1.0.2 ~
/origin example.org. ~
www.% 10.2.0.1 ~
% MX 10 mail.% ~
mail.% 10.2.0.2 ~
Which is equivalent to:
www.example.com. 10.1.0.1 ~
example.com. MX 10 mail.example.com. ~
mail.example.com. 10.1.0.2 ~
www.example.org. 10.2.0.1 ~
example.org. MX 10 mail.example.org. ~
mail.example.org. 10.2.0.2 ~
It is also possible to make the current origin be part of the new origin:
/origin example.com. ~
% 10.3.2.1 ~ # example.com now has IP 10.3.2.1
/origin mail.% ~
% 10.3.2.2 ~ # mail.example.com now has IP 10.3.2.2
The '/opush' and '/opop' slash commands use a stack to remember and later recall values for the origin (see origin above). The '/opush' command is used just like the '/origin' command; however, the current origin is placed on a stack instead of discarded. The '/opop' command removes ("pops") the top element from this stack and makes the element the origin.
For example:
/origin example.com. ~
/opush mail.% ~ # origin is now mail.example.com; example.com is on stack
a.% 10.4.0.1 ~ # a.mail.example.com has IP 10.4.0.1
/opush web.example.com. ~ # mail.example.com and example.com are on stack
a.% 10.5.0.1 ~ # a.web.example.com has IP 10.5.0.1
b.% 10.5.0.2 ~ # b.web.example.com has IP 10.5.0.2
/opop ~ # origin is now mail.example.com again
b.% 10.4.0.2 ~ # b.mail.example.com has IP 10.4.0.2
/opop ~ # origin is now example.com
% MX 10 a.mail.% ~ # example.com. MX 10 a.mail.example.com.
% MX 20 b.mail.% ~ # example.com. MX 20 b.mail.example.com.
The opush/opop stack can have up to seven elements on it.
The '/read' slash commands allows one to have the contents of another file in a zone. The '/read' command takes a single argument: A filename that one wishes to read. The filename is only allowed to have letters, numbers, the '-' character, the '_' character, and the '.' character in it.
The file needs to be in the same directory as the zone file. The file will be read with the same privileges as the zone file; content in the file should come from a trusted source or be controlled by the system administrator.
Let us suppose that we have the following in a zone file:
mail.foo.example.com. 10.3.2.1 ~
/read foo ~
foo.example.com. MX 10 mail.foo.example.com. ~
And a file foo with the following contents:
foo.example.com. 10.1.2.3 ~
foo.example.com. TXT 'Foomatic!' ~
Then foo.example.com will have an A record with the value 10.1.2.3, a TXT value of 'Foomatic!', and a MX record with priority 10 pointing to mail.foo.example.com. mail.foo.example.com will have the IP 10.3.2.1.
Note that no pre-processing nor post-processing of the origin is done by the '/read' command; should the file read change the origin, this changed value will affect any records after the '/read' command. For example, let us suppose db.example.com looks like this:
/origin foo.example.com. ~
% TXT 'Foomatic!' ~
/read foo ~
% MX 10 mail.foo.example.com. ~
And the file foo looks like this:
% 10.1.2.3 ~
/origin mail.% ~
% 10.3.2.1 ~
Then the following records will be created:
foo.example.com. TXT 'Foomatic!' ~
foo.example.com. A 10.1.2.3 ~
mail.foo.example.com. A 10.3.2.1 ~
mail.foo.example.com. MX 10 mail.foo.example.com. ~
To have something that works like '$INCLUDE filename' in a RFC1035 master file, do the following:
/opush % ~
/read filename ~
/opop ~
Or, for that matter, the equivalent of '$INCLUDE filename neworigin':
/opush neworigin. ~
/read filename ~
/opop ~
## This is an example csv2 zone file
## First of all, csv2 zone files do not need an SOA record; however, if
## one is provided, we will make it the SOA record for our zone
## The SOA record needs to be the first record in the zone if provided
## This is a commented out record and disabled.
#% SOA % email@% 1 7200 3600 604800 1800 ~
## Second of all, csv2 zone files do not need authoritative NS records.
## If they aren't there, MaraDNS will synthesize them, based on the IP
## addresses MaraDNS is bound to. (She's pretty smart about this; if
## Mara is bound to both public and private IPs, only the public IPs will
## be synthesized as NS records)
#% NS a.% ~
#% NS b.% ~
## Here are some A (ipv4 address) records; since this is the most
## common field, the zone file format allows a compact representation
## of it.
a.example.net. 10.10.10.10 ~
## Here, you can see that a single name, "b.example.net." has multiple IPs
## This can be used as a primitive form of load balancing; MaraDNS will
## rotate the IPs so that first IP seen by a DNS client changes every time
## a query for "b.example.net." is made
b.example.net. 10.10.10.11 ~
b.example.net. 10.10.10.12 ~
## We can have the label in either case; it makes no difference
Z.EXAMPLE.NET. 10.2.3.4 ~
Y.EXAMPLE.net. 10.3.4.5 ~
## We can use the percent shortcut. When the percent shortcut is present,
## it indicates that the name in question should terminate with the name
## of the zone we are processing.
percent.% a 10.9.8.7 ~
## And we can have star records
#*.example.net. A 10.11.12.13 ~
## We can have a ttl in a record; however the ttl needs a '+' before it:
## Note that the ttl has to be in seconds, and is before the RTYPE
d.example.net. +86400 A 10.11.12.13 ~
f.example.net. # As you can see, records can span multiple lines
A 10.2.19.83 ~
## This allows well-commented records, like this:
c.example.net. # Our C class machine
+86400 # This record is stored for one day
A # A record
10.1.1.1 # Where we are
~ # End of record
## We can even have something similar to csv1 if we want...
e.example.net.|+86400|a|10.2.3.4|~
h.example.net.|a|10.9.8.7|~
## Here, we see we can specify the ttl but not the rtype if desired
g.example.net.|+86400|10.11.9.8|~
## Here is a MX record
## Note that "IN" is a pseudo-RR which means to ignore the RR type and
## look at the next RR type in the zone file; this allows MaraDNS zone
## files to look more like BIND zone files.
% mx 10 mail.% ~
mail.% +86400 IN A 10.22.23.24 ~
## We even have a bit of ipv6 support
a.example.net. aaaa 2001:db8:1:2::3:f ~
## Not to mention support for SRV records
_http._tcp.% srv 0 0 80 a.% ~
## TXT records, naturally
example.net. txt 'This is some text' ~
## Starting with MaraDNS 1.2.08, there is also support for SPF records,
## which are identical to TXT records. See RFC4408 for more details.
example.net. spf 'v=spf1 +mx a:colo.example.com/28 -all' ~
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Sam Trenholme http://www.samiam.org/
csv2_txt - Description of txt and raw resource records in the csv2 zone file
Due to the complexity of TXT and RAW records, this man page is dedicated to describing the csv2 format of this RR.
TXT and RAW rrs in MaraDNS' csv2 zone files can store any arbitrary binary data. Additionally, it is possible to arbitrarily divide up TXT records in to chunks (chunks, which RFC1035 call "character-string"s, are described below).
If a given TXT field or RAW record contains only ASCII data, creating a record is easy: Place the full data between single quotes, like this:
a.example.com. TXT 'This is some text' ~
It is also possible, to place almost any printable ASCII
characters between quotes. The '~' (tilde) character is not allowed
unless csv2_tilde_handling has a value of 0; the '|' (pipe), '#' (hash)
and non-printable ASCII control characters are not allowed in TXT data
if the ~ is used to separate records. If there are any bytes with a
value of 0x80 or more, the data must be UTF-8 encoded Unicode.
For example:
b.example.com. TXT 'This is an example UTF-8 character: I ♥ MaraDNS'
(If your font does not have this Unicode symbol, it is a heart)
The printable ASCII characters not allowed in quotes are the ' character, the '|' character, the '~' (tilde) character, and the '#' character. See BACKSLASH ESCAPE SEQUENCES below for information on adding these characters to TXT or RAW fields.
Note that the record does not have to be quoted. As long as the record only contains ASCII alphanumeric data, and/or the characters '-', '_', '+', '%', '!', '^', and '=', the data can be unquoted as follows:
c.example.com. TXT This_is_100%_unquoted_text_+symbols!
It is also possible to mix quoted and unquoted text, such as this:
d.example.com. TXT This' is a mix 'of_unquoted' and quoted 'text!
Which will have its data look like this:
This is a mix of_unquoted and quoted text!
When mixing quoted and unquoted data, it is important to have all whitespace inside quotes.
In order to accommodate storing non-UTF-8 high bit characters, the single quote character, non-printable ASCII control codes, the '|', '~', and '#' characters, and to permit multi-line TXT/RAW records (with comments allowed mid-record), the TXT/RAW RR allows backslashes. These backslashes only have significance outside of quoted text; if they are placed inside single quotes, they are not interpreted and result in a literal backslash being added to the resource record data.
The following characters can be backslashed:
'
When backslashed, the adds a literal quote to the resource record.
whitespace
When any whitespace is backslashed (space, newline, cr,
and tab), this indicates that the record has not ended, and that more
data for this resource will follow. This also allows comments to be
placed in TXT and RAW resource records. What happens is that the
backslash indicates that any whitespace characters (space, tab,
carriage return, and line feed) are to be ignored until the next
non-whitespace character that is not a # (hash). If a # is seen, this
indicates that we ignore any and all characters until the next carriage
return or line feed, and continue to ignore everything until the next
non-whitespace character. See the section on multi-line and commented
records for examples.
0123
When a number between 0 and 3 is backslashed, this indicates the
beginning of a three-digit octal number.
x
When an x is backslashed, this indicates the beginning of a
two-digit hexadecimal number. Note that, with the exception of
the single quote, the backslash character is not used to remove the
meta-significance of a given character. In particular, unlike other
environments, it is not possible to backslash spaces. Spaces can be
represented either as ' ' in quotes, \x20, or as \040.
Here are some examples of backslashed data. In this example, we see backslash sequences being used to store non-UTF-8 hi-bit data:
e.example.com. TXT \x80\x81\x82\x83 ~
This same data can also be created as follows:
f.example.com. TXT \200\201\202\203 ~
Octal and hex information can be mixed:
g.example.com. TXT \200\x81\202\x83 ~
Literal single quotes can be placed in resource records:
h.example.com. TXT 'perl -e '\''print "A Perl of a TXT record!\n"'\' ~
The above example produces this record:
perl -e 'print "A Perl of a TXT record!\n"' ~
To render the '~' character, use the escape sequence \x7e (outside of quotes). For example:
h1.example.com. TXT 'http://ocf.berkeley.edu/'\x7e'set' ~
Produces this record:
http://ocf.berkeley.edu/~set
To render the '|' character, use the escape sequence \x7c:
h2.example.com. TXT 'ls '\x7c' more' ~
Produces this record:
ls | more
To render the '#' character, use the escape sequence \x23:
h3.example.com. TXT 'Press '\x23' for customer service' ~
Produces this record:
Press # for customer service
By utilizing backslashes followed by comments, it is possible to have multi-line and commented TXT and RAW records. The following resource record will span more than one line on an 80-column display:
i.example.com. TXT 'Not only did the quick brown fox jump over the lazy dog, but the lazy dog jumped over the cat.' ~
Without affecting this resource record, the same data can be split over multiple lines:
j.example.com. TXT 'Not only did the quick brown fox jump '\
'over the lazy dog, but the lazy dog'\
' jumped over the cat.' ~
Some points:
-
The backslash must be outsize of the quotes (or a literal backslash will be added to the record)
-
The backslash must be present before any unquoted white space. Usually, the backslash is placed immediately after the quote character.
-
Unlike other environments, it does not matter whether or not there is invisible whitespace after the backslash.
It is also possible to add comments after such a backslash as follows:
k.example.com. TXT 'Not only did the quick brown fox jump '\ # The fox
'over the lazy dog, but the lazy dog'\ # The dog
' jumped over the cat.' ~ # The cat
Note that, since the third comment is not preceded by a backslash, this indicates the end of the resource record.
There can also be multiple lines dedicated to comments (and, optionally, even blank lines) in the middle of TXT and RAW record data:
k2.example.com. TXT 'This is some data '\
# Here we have some comments followed by a blank line
# Now we have some more comments,
# followed by the rest of the data
'and this is the rest of the data' ~
TXT RRs may be divided up in to multiple "chunks" (RFC1035 calls these "character-string"s). A single chunk can be anywhere from zero to 255 bytes long. The default is to have one chunk, as follows:
o.example.com. TXT 'TXT record with only one chunk' ~
It is also possible to have a record with multiple chunks. Chunks are delimited by an unquoted ';' character:
p.example.com. TXT 'This is chunk one';'This is chunk two' ~
Or:
q.example.com. TXT 'This is chunk one';\ # Our first chunk
This_is_chunk_two;\ # Our second chunk
'This is chunk three' ~ # Our final chunk
Quoted ; characters simply add a ; to the record data.
If a single TXT chunk is longer than 255 bytes long, the csv2 parser will report an error in the zone file: Single TXT chunk too long
In order to resolve this, place unquoted ; characters in the record data so that each chunk is under 255 octets (bytes or characters) in length.
It is possible to have zero length chunks:
r.example.com. TXT 'chunk one';;'chunk three' ~ # Chunk two zero-length
In particular, is is possible to have zero length chunks at the beginning and end of a TXT record:
s.example.com. TXT ;'chunk two'; ~ # Chunks one and three zero-length
Do not place semicolons at the beginning nor end of TXT records unless you wish to have these zero-length chunks.
Chunk support only exists for TXT records. An unquoted ; character will cause a syntax error in a RAW record.
With the exception of no support for chunk delimiters, and the addition of a numeric record type before the record data, the format for RAW records is identical to text records. For example, if we wish to have a "Kitchen Sink" RR record, which has the 8-bit binary numbers "16", "1", and "2", followed by the ASCII string "Kitchen sink+ data", we can specify this in any of the following manners:
t1.example.com. RAW 40 \x10\x01\x02'Kitchen sink'\x2b' data' ~
t.example.com. RAW 40 \020\001\002Kitchen' sink+ data' ~
u.example.com. RAW 40 \x10\x01\x02Kitchen\x20sink+\x20data ~
v.example.com. RAW 40 \x10\001\x02\
'Kitchen sink+ data' ~
w.example.com. RAW 40 \x10\ # Meaning: 16
\x01\ # Coding: 1
\x02\ # Sub-coding: 2
'Kitchen sink+ data' ~ # Data: 'Kitchen sink+ data'
DKIM is a format used to store e-mail authentication data via DNS.
MaraDNS can store a 2048-bit RSA DKIM key. Longer keys are not supported because of the 512-byte limit for traditional DNS packets.
A DKIM record is a long “multi chunk” TXT record; DKIM records are
stored in a special _domainkey.example.com
record. As per RFC6376
section 3.6.2.2, “Strings in a TXT RR MUST be concatenated together
before use with no intervening whitespace”; a single TXT “chunk” can
only be up to 255 bytes in length, but we need more than 255 bytes to
store a 2048 bit RSA key (6 bits per character, so we need 342
characters to store just the key) and a little more overhead to store
the other bits in our DKIM record. But, it doesn’t matter where we
split the chunks as long as each individual chunk is under 256 bytes in
size.
Here is a real-world DKIM key stored in a MaraDNS zone file:
x._domainkey.% +600 TXT 'v=DKIM1; k=rsa; '\
'p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCg'\
'KCAQEAuhKjx2Aepa3rllxUEZLgF3x'\
'68SWvZ8pEgnjZvxtqp94Vkra3AUC4C8dRLKf5SvT'\
'xFtIl6pF27jn+M/w2MzYwPFjBgqVf'\
'p2lf7xuKsrus63m0T9Sq958nIt1yuUlLDr71bFs7'\
'ZuZyQid0ciCc2JF5lwHno10cAvuNJ';'y1Q'\
'tFJa+lRJI6/kzY20Hi/ZTzFzctqgqaRZnSoJlTZHf'\
'Oy0uwfmF5ejkJ8xvHbEJp6TEc'\
'30DwsqrjVWSFLnUWYBv7lrAPB9sAHN7fCayhEuORn'\
'Ap+YUhjjMPWyPla1pvTS9h/LTE7g'\
'2d+jR/zOkRpV2Ak/4KpeP9dpsRJEOsPEaWGG1pQXgPw'\
'IDAQAB'
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Sam Trenholme http://www.samiam.org/
duende - run a child process as a daemon
duende is a tool for users of init systems which require programs to provide their own daemonization. duende is not needed with systemd and other init systems which can provide daemonization for network services. duende makes a given child process a daemon. The standard output and standard error of the child process is logged via syslog() with a priority of LOG_INFO.
duende should not be used if one uses systemdas the init process. Instead, files like this should be added to
/etc/systemd/system`
# Place this file here:
# /etc/systemd/system/maradns.service
# Then
# systemctl enable maradns
# systemctl start maradns
# To view log
# journalctl -u maradns
[Unit]
After=network-online.target
ConditionPathExists=/usr/local/bin/maradns
Description=MaraDNS
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/maradns
StandardOutput=journal
TimeoutSec=0
Type=exec
[Install]
WantedBy=multi-user.target
When installed with make install
, MaraDNS will look for systemd
files, and install MaraDNS and Deadwood startup files.
duende (--pid=/path/to/file) child_process [ all subsequent arguments passed on to child ]
When duende is invoked, it spawns two processes. In addition to
spawning the daemonized child process, duende also spawns a process
which reads and logs the standard output of the daemonized process. The
parent process stays alive so as to monitor the daemonized process. If
the optional --pid
argument is supplied, duende will write its
PID to the file specified by the argument. It is an error to supply the
--pid
argument without an equal sign and file name.
duende requires a blank directory named /etc/maradns/logger
to
run.
Should the parent duende process a HUP signal, duende will restart the child process. Should the daemonized or logging process received an untrapped HUP signal or exit with an exit code of 8, duende will restart the process. Should the daemonized or logging process exit for any other reason, duende will send the logger process a TERM signal and exit. Should the duende parent process receive a TERM or INT signal, duende sends all of its children TERM signals, then exits.
The duende process must be started as the superuser; this is because Duende's intended child processes (maradns and zoneserver) need to bind to privileged ports, and because duende uses a setuid() call to change the user ID of the logging process to the user with ID 707.
duende uses the syslog() facility to log the standard output of the program that it invokes. The name of the program (in other words, the "ident" given to openlog()) is the full path of the first argument given to duende. All messages created by the child process are sent to syslog() with a priority of LOG_INFO and a "facility" of LOG_DAEMON (daemon.info in /etc/syslog.conf); since daemon.info messages are not logged by default in FreeBSD, on FreeBSD systems messages generated by the child process are logged with a priority of LOG_ALERT and a "facility" of LOG_DAEMON (daemon.alert in /etc/syslog.conf). Should duende itself encounter an error, it will send messages to syslog() with a priority of LOG_ALERT.
For example, suppose one invokes duende thusly:
duende /usr/local/sbin/maradns
If invoked thusly, duende will log all messages with the "ident" (program name) of "/usr/local/sbin/maradns". If this is not desired, invoke duende with something like:
export PATH=$PATH:/usr/local/sbin
duende maradns
This will log messages with a (more sensible) "ident" of maradns.
Note: If a non-POSIX Bourne shell (such as csh, es, rc, or fish) is used to invoke MaraDNS, the above syntax needs to be changed.
Also, the directory /etc/maradns/logger, while used by duende, is not used to store any log messages. That is unless, for some reason, one configures syslog to store messages there.
Using duende to start maradns, where the mararc file is /etc/mararc.2
duende maradns -f /etc/mararc.2
Using duende to start zoneserver, where the mararc file is /etc/mararc.4
duende zoneserver -f /etc/mararc.4
Duende assumes that all of its children are well-behaved, eating their vegetables, going to bed when told, and terminating when receiving a TERM signal.
maradns(8), syslog(3) http://www.maradns.org
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Duende and this man page are written by Sam Trenholme. D Richard Felker III provided some invaluable assistance with the piping code which duende uses.
fetchzone - get dns zone from server
fetchzone transfers a user-specified dns zone from a zone server and displays it in csv2 format on the standard output.
fetchzone zone_name zone_server_IP [query_class]
zone_name
Name of the dns zone to be transferred.
zone_server_IP
IP address of dns server
query_class
Optional argument which can change the query class from 1 (the default) to 255. This may be needed for some versions of Bind.
To obtain the zone example.com from the server 192.168.9.8:
fetchzone example.com 192.168.9.8
To obtain the zone example.org from the server 10.9.8.78 using a query class of 255:
fetchzone example.com 10.9.8.78 255
Fetchzone will not correctly output host names with utf-8 characters in them.
The man pages maradns(8) and csv2(5)
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Sam Trenholme
getzone - get dns zone from server
getzone transfers a user-specified dns zone from a zone server and displays it in csv1 format on the standard output. This program is here for compatibility with older setups that use getzone to get zone files; newer setups may wish to consider using the fetchzone tool to obtain csv2-compatible zone files.
getzone zone_name zone_server_IP [query_class]
zone_name
Name of the dns zone to be transferred.
zone_server_IP
IP address of dns server
query_class
Optional argument which can change the query class from 1 (the default) to 255. This may be needed for some versions of Bind.
To obtain the zone example.com from the server 192.168.9.8:
getzone example.com 192.168.9.8
To obtain the zone example.org from the server 10.9.8.78 using a query class of 255:
getzone example.com 10.9.8.78 255
The man pages maradns(8) and csv1(5)
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MaraDNS is written by Sam Trenholme. Jaakko Niemi used 5 minutes to put this manpage together. Sam has subsequently made revisions to this manpage.
Erre con erre cigarro
Erre con erre barril
Rápido ruedan los carros
En el ferrocarril
maradns - DNS server
maradns [ -v | -f mararc_file_location ]
This man page has the following sections:
Name
Synopsis
Table of Contents
Description
Usage
Firewall Configuration
Frequently Asked Questions
Bugs
Unimplemented Features
Legal Disclaimer
Authors
maradns is a DNS server written with security, simplicity, and performance in mind.
maradns has two forms of arguments, both of which are optional.
The first is the location of a mararc file which MaraDNS obtains all configuration information from. The default location of this file is /etc/mararc. This is specified in the form maradns -f mararc_file_location; mararc_file_location is the location of the mararc file.
It is also possible to have MaraDNS display the version number and exit. This is specified by invoking maradns in the form maradns -v or maradns --version
MaraDNS consists of two programs: maradns, an authoritative-only nameserver, and Deadwood, a recursive name server. Deadwood has its own man page.
In order for MaraDNS to function as an authoritative nameserver, two or more files need to be set up: the mararc file and one or more "csv2" (or "csv1") zone files.
The format of a csv2 zone file can be obtained from the csv2(5) manual page. The configuration format of the mararc file can be obtained from the mararc(5) manual page.
Please note that, in order to reload a zone file, it is necessary to restart MaraDNS and reload all zone files. MaraDNS uses a hash data format which loads records very quickly from memory, but requires a restart to update.
In order to have MaraDNS run as a daemon, the duende program is used to daemonize MaraDNS. See the duende(8) manual page for details.
When using the maradns authoritative nameserver, allow UDP connections from all hosts on the internet to UDP port 53 for the IP that the authoritative nameserver uses.
When using the Deadwood recursive nameserver:
-
Allow UDP connections from the Deadwood server to any machine on the internet where the UDP destination port is 53
-
Allow UDP connections from any machine on the internet to the IP of the recursive server, where the source port from the remote server is 53, and the destination port is between 15000 and 19095 (inclusive)
-
Allow UDP connections from IPs that use Deadwood as a recursive DNS server to port 53
Deadwood uses a strong secure RNG (RadioGatun[32]) for both the query (16 bits of entropy) and the source port of the query (12 bits of entropy). This makes spoofing replies to a Deadwood recursive server more difficult, since the attacker has only a one in 250 million chance that a given spoofed reply will be considered valid.
-
I'm using an older version of MaraDNS
-
How do I try out MaraDNS?
-
What license is MaraDNS released under?
-
How do I report bugs in MaraDNS?
-
Some of the postings to the mailing list do not talk about MaraDNS!
-
How do I get off the mailing list?
-
How do I set up reverse DNS on MaraDNS?
-
I am on a slow network, and MaraDNS can not process recursive queries
-
When I try to run MaraDNS, I get a cryptic error message.
-
After I start MaraDNS, I can not see the process when I run netstat -na
-
What string library does MaraDNS use?
-
Why does MaraDNS use a multi-threaded model?
-
I feel that XXX feature should be added to MaraDNS
-
I feel that MaraDNS should use another documentation format
-
Is there any process I need to follow to add a patch to MaraDNS?
-
Can MaraDNS act as a primary nameserver?
-
Can MaraDNS act as a secondary nameserver?
-
What is the difference between an authoritative and a recursive DNS server?
-
The getzone client isn't allowing me to add certain hostnames to my zone
-
Is MaraDNS portable?
-
Can I use MaraDNS in Windows?
-
MaraDNS freezes up after being used for a while
-
What kind of Python integration does MaraDNS have
-
Doesn't "kvar" mean "four" in Esperanto?
-
How scalable is MaraDNS?
-
I am having problems setting
upstream_servers
-
Why doesn't the MaraDNS.org web page validate?
-
How do MX records work?
-
Does MaraDNS have support for SPF?
-
I'm having problems resolving CNAMES I have set up.
-
I have a NS delegation, and MaraDNS is doing strange things.
-
I am transferring a zone from another server, but the NS records are these strange "synth-ip" records.
-
Where is the root.hints file?
-
Are there any plans to use autoconf to build MaraDNS?
-
How do I change the compiler or compile-time flags with MaraDNS' build process?
-
Will you make a package for the particular Linux distribution I am using?
-
I am using the native Windows port of MaraDNS, and some features are not working.
-
MaraDNS isn't starting up
-
You make a lot of releases of MaraDNS; at our ISP/IT department, updating software is non-trivial.
-
I have star records in my zones, and am having problems with NXDOMAINs/IPV6 resolution
-
I have a zone with only SOA/NS records, and the zone is not working.
-
I am having problems registering my domain with AFNIC (the registrar for .fr domains)
-
I can't see the full answers for subdomains I have delegated
-
MaraDNS 1 has a problem resolving a domain
-
MaraDNS 1.2 has issues with NXDOMAINS and case sensitivity.
-
Can MaraDNS offer protection from phishing and malicious sites?
-
Does maradns support star (wildcard) records?
-
I'm having problems using MaraDNS with some *NIX command line applications like telnet
-
My virus scanner reports that MaraDNS or Deadwood has a virus
-
I can not subscribe to the MaraDNS mailing list
-
How does MaraDNS respond to EDNS (RFC2671) packets?
-
How to I get MaraDNS to always give the same IP to all DNS queries?
-
Why did you change MaraDNS' tagline?
-
How do you stop MaraDNS from taking part in a distributed denial-of-service attack?
-
What about DNS-over-TCP?
-
How do I use MaraDNS with systemd?
-
Why doesn't MaraDNS use IP_FREEBIND?
-
Is there a web interface for MaraDNS?
-
What does the message “don’t forget the trailing dot” mean?
-
Does MaraDNS support newer top level domains?
-
Can MaraDNS handle IDN domain names?
Upgrade to MaraDNS 2.0. Here is an upgrade guide.
MaraDNS 1 is no longer supported; support ended on June 21, 2015.
Read the quick start guide, which is the file named 0QuickStart in the MaraDNS distribution.
MaraDNS is released with the following two-clause BSD-type license:
Copyright (c) 2002-2016 Sam Trenholme and others
TERMS
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
This software is provided 'as is' with no guarantees of correctness or fitness for purpose.
Post your bug report as a Github issue.
As of September 2013, the mailing list has become moderated and only postings on the mailing list are relevant MaraDNS announcements.
Send an email to [email protected], or an email to [email protected] with "unsubscribe" as the subject line.
The mailing list will send you an email confirming the unsubscribe request; this email needs to be replied to in order to get off the list.
Reverse DNS (sometimes called "reverse mapping") is set up by using PTR (pointer) records. For example, the PTR record which performs the reverse DNS lookup for the ip 10.2.3.4 looks like this in a CSV2 zone file:
4.3.2.10.in-addr.arpa. PTR www.example.com.
It is also possible to use a special "FQDN4" which automatically sets up the reverse mapping of a given record:
www.example.com. FQDN4 10.2.3.4
If you wish to have a PTR (reverse DNS lookup; getting a DNS name from a numeric IP) record work on the internet at large, it is not a simple matter of just adding a record like this to a MaraDNS zonefile. One also needs control of the appropriate in-addr.arpa. domain.
While it could make logical sense to contact the IP 10.11.12.13 when trying to get the reverse DNS lookup (fully qualified domain name) for a given IP, DNS servers don't do this. DNS server, instead, contact the root DNS servers for a given in-addr.arpa name to get the reverse DNS lookup, just like they do with any other record type.
When an internet service provider is given a block of IPs, they are also given control of the DNS zones which allow them to control reverse DNS lookups for those IPs. While it is possible to obtain a domain and run a DNS server without the knowledge or intervention of an ISP, being able to control reverse DNS lookups for those IPs requires ISP intervention.
Deadwood, by default, only waits two seconds for a reply from a remote DNS server. This default can be increased by adding a line like this in the mararc file:
timeout_seconds = 5
Note that making this too high will slow MaraDNS down when DNS servers are down, which is, alas, all too common on today's internet.
There is usually some context of where there is a syntax error in a data file before the cryptic error message. For example, when there is a syntax error in a csv2 zone file, MaraDNS will tell you exactly at what point it had to terminate parsing of the zone file.
If MaraDNS does return a cryptic error message without letting you know what is wrong, let us know in a Github issueso that we can fix the bug. MaraDNS is designed to be easy to use; cryptic error messages go against this spirit.
netstat -na
Udp services do not have a prominent "LISTEN" when netstat is run.
When MaraDNS is up, the relevant line in the netstat output looks like
this: udp 0 0 127.0.0.1:53 0.0.0.0:*
While on the topic of netstat, if you run netstat -nap
as root on
Linux and some other *nix operating systems, you can see the names of
the processes which are providing internet services.
MaraDNS uses its own string library, which is called the "js_string"
library. Man pages for most of the functions in the js_string library
are in the folder doc/man
of the MaraDNS distribution
MaraDNS 2.0 no longer uses threads.
It took me three years to rewrite MaraDNS' recursive resolver as a separate non-threaded daemon. This has been done, and now all recursion is done with Deadwood which does not need threads.
There are no plans to add new features to MaraDNS or Deadwood at this time.
The reason that MaraDNS uses its own documentation format is to satisfy both the needs of translators to have a unified document format and my own need to use a documentation format that is simple enough to be readily understood and which I can add features on an as needed basis.
The documentation format is essentially simplified HTML with some special tags added to meet MaraDNS' special needs.
This gives me more flexibility to adapt the documentation format to changing needs. For example, when someone pointed out that it's not a good idea to have man pages with hi-bit characters, it was a simple matter to add a new HIBIT tag which allows man pages to be without hi-bit characters, and other document formats to retain hi-bit characters.
Having a given program have its own documentation format is not without precedent; Perl uses its own "pod" documentation format.
I no longer accept third party patches
Yes.
The zoneserver
program serves zones so that other DNS servers can be
secondaries for zones which MaraDNS serves. This is a separate program
from the maradns
server, which processes authoritative UDP DNS
queries, and Deadwood which processes recursive DNS queries.
See the DNS masterdocument in the MaraDNS tutorial for details.
Yes.
Please read the DNS slavedocument, which is part of the MaraDNS tutorial.
DNS server?
A recursive DNS server is a DNS server that is able to contact other
DNS servers in order to resolve a given domain name label. This is the
kind of DNS server one points to in /etc/resolv.conf
. MaraDNS uses
the Deadwood daemon to process recursive DNS queries.
An authoritative DNS server is a DNS server that a recursive server contacts in order to find out the answer to a given DNS query. The maradns daemon processes authoritative DNS queries.
to my zone
For security reasons, MaraDNS' fetchzone client does not add records which are not part of the zone in question. For example, if someone has a zone for example.com, and this record in the zone:
1.1.1.10.in-addr.arpa. PTR dns.example.com.
MaraDNS will not add the record, since the record is out-of-bailiwick. In other words, it is a host name that does not end in .example.com.
There are two workarounds for this issue:
-
Create a zone file for 1.1.10.in-addr.arpa., and put the PTR records there.
-
Use rcp, rsync, or another method to copy over the zone files in question.
MaraDNS is developed in CentOS 6 and Windows 7. MaraDNS may or may not compile and run on other systems.
Yes. There is both a partial mingw32 (native win32 binary) port and a full Cygwin port of MaraDNS; both of these ports are part of the native build of MaraDNS. Deadwood has full Windows support, including the ability to run as a service.
If using your ISP's name servers or some other name servers which are not, in fact, root name servers, please make sure that you are using the upstream_servers dictionary variable instead of the root_servers dictionary variable.
If you still see MaraDNS freeze up after making this correction, please send a bug report as a Github issue.
The mararc file uses the same syntax that Python uses; in fact, Python can parse a properly formatted mararc file.
There is no other integration with Python.
Indeed, it does. However the use of "kvar" in the MaraDNS source code only coincidentally is an Esperanto word. "kvar" is short for "Kiwi variable"; a lot of the parsing code comes from the code used in the Kiwi spam filter project.
MaraDNS is optimized for serving a small number of domains as quickly as possible. That said, MaraDNS is remarkably efficnent for serving a large number of domains, as long as the server MaraDNS is on has the memory to fit all of the domains, and as long as the startup time for loading a large number of domains can be worked around.
The "big-O" or "theta" growth rates for various MaraDNS functions are as follows, where N is the number of authoritative host names being served:
Startup time N
Memory usage N
Processing incoming DNS requests 1
As can be seen, MaraDNS will process 1 or 100000 domains in the same amount of time, once the domain names are loaded in to memory.
upstream_servers
is only supported by Deadwood, and is no longer
supported in MaraDNS 2.0. The upstream_servers
dwood3rc variable is
set thusly:
upstream_servers["."] = "10.3.28.79, 10.2.19.83"
Note the ["."]
.
Note that the upstream_servers
variable needs to be initialized
before being used via upstream_servers = {}
(the reason for this is
so that a dwood3rc file has 100% Python-compatible syntax). A complete
dwood3rc file that uses upstream_servers
may look like this:
ipv4_bind_addresses = "127.0.0.1"
chroot_dir = "/etc/maradns"
recursive_acl = "127.0.0.1/8"
upstream_servers = {}
upstream_servers["."] = "10.1.2.3, 10.2.4.6"
HTML pages on the MaraDNS.org web site should validate as HTML 4.0 Transitional. However, the CSS will not validate.
I have designed MaraDNS' web page to be usable and as attractive as possible in any major browser released in the last ten years. Cross-browser support is more important than strict W3 validation. The reason why the CSS does not validate is because I need a way to make sure there is always a scrollbar on the web page, even if the content is not big enough to merit one; this is to avoid the content jumping from page to page. There is no standard CSS tag that lets me do this. I'm using a non-standard tag to enable this in Gecko (Firefox's rendering engine); this is enabled by default in Trident (Internet Explorer's rendering engine). The standards are deficient and blind adherence to them would result in an inferior web site.
There are also two validation warnings generated by redefinitions which are needed as part of the CSS filters used to make the site attractive on older browsers with limited CSS support.
On a related note, the reason why I use tables instead of CSS for some
of the layout is because Microsoft Internet Explorer 6 and other
browsers do not have support for the max-width
CSS property. Without
this property, the web page will not scale down correctly without using
tables. Additionally, tables allow a reasonably attractive header in
browsers without CSS support.
How MX records work:
-
The mail transport agent (Sendmail, Postfix, Qmail, MS Exchange, etc.) looks up the MX record for the domain
-
For each of the records returned, the MTA (mail transport agent) looks up the IP for the names.
-
It will choose, at random, any of the MXes with the lowest priority number.
-
Should that server fail, it will try another server with the same priority number.
-
Should all MX records with a given priority number fail, the MTA will try sending email to any of the MX records with the second-lowest priority value.
As an aside, do not have MX records point to CNAMEs.
SPF, or sender policy framework, is method of using DNS that makes it more difficult to forge email. MaraDNS has full support for SPF, both via TXT records and RFC4408 SPF records.
SPF configuration is beyond the scope of MaraDNS' documentation.
However, at the time this FAQ entry was last updated (July, 2013),
information and documentation concerning SPF is available at
http://openspf.org. The BIND examples will work in MaraDNS csv2 zone
files as long as the double quotes (") are replaced by single quotes
('). For example, a SPF TXT record that looks like example.net. IN TXT "v=spf1 +mx a:colo.example.com/28 -all"
in a BIND zone file will look
like example.net. TXT 'v=spf1 +mx a:colo.example.com/28 -all'
in a
MaraDNS zone file. MaraDNS can also make the corresponding SPF record,
which will have the syntax example.net. SPF 'v=spf1 +mx a:colo.example.com/28 -all'
.
Use '\x7e' to put a tilde ("~" character) in a SPF record:
example.com. SPF 'v=spf1 +mx a:colo.example.com/28 '\x7e'all'
This is probably because you have set up what MaraDNS calls a dangling CNAME record.
Let us suppose we have a CNAME record without an A record in the local DNS server's database, such as:
google.example.com. CNAME www.google.com.
This record, which is a CNAME record for "google.example.com", points to "www.google.com". Some DNS servers will recursively look up www.google.com, and render the above record like this:
google.example.com. CNAME www.google.com.
www.google.com. A 66.102.7.104
For security reasons, MaraDNS doesn't do this. Instead, MaraDNS will simply output:
google.example.com. CNAME www.google.com.
Some stub resolvers will be unable to resolve google.example.com as a consequence.
If you set up MaraDNS to resolve CNAMEs thusly, you will get a warning in your logs about having a dangling CNAME record.
If you want to remove these warnings, add the following to your mararc file:
no_cname_warnings = 1
Information about how to get MaraDNS to resolve dangling CNAME records is in the tutorial file dangling.html
This is only an issue in MaraDNS 1.4. MaraDNS 2.0 does not allow the same IP to both authoritatively and recursively resolve records.
are these strange "synth-ip" records.
MaraDNS expects, in csv2 zone files, for all delegation NS records to be between the SOA record and the first non-NS record.
If a zone looks like this:
example.net. +600 soa ns1.example.net.
[email protected] 10 10800 3600 604800 1080
example.net. +600 mx 10 mail.example.net.
example.net. +600 a 10.2.3.5
example.net. +600 ns ns1.example.net.
example.net. +600 ns ns3.example.net.
mail.example.net. +600 a 10.2.3.7
www.example.net. +600 a 10.2.3.11
Then the NS records will be "synth-ip" records.
The zone should look like this:
example.net. +600 soa ns1.example.net.
[email protected] 10 10800 3600 604800 1080
example.net. +600 ns ns1.example.net.
example.net. +600 ns ns3.example.net.
example.net. +600 mx 10 mail.example.net.
example.net. +600 a 10.2.3.5
mail.example.net. +600 a 10.2.3.7
www.example.net. +600 a 10.2.3.11
This will remove the "synth-ip" records.
To automate this process, this awk script is useful:
fetchzone whatever.zone.foo 10.1.2.3 | awk '
{if($3 ~ /ns/ || $3 ~ /soa/){print}
else{a = a "\n" $0}}
END{print a}' > zonefile.csv2
Replace "whatever.zone.foo" with the name of the zone you are fetchin 10.1.2.3 with the IP address of the DNS master, and zonefile.csv2 with the name of the zone file MaraDNS loads.
MaraDNS (actually, Deadwood), unlike BIND, does not need a complicated root.hints file in order to have custom root servers. In order to change the root.hints file, add something like this to your dwood3rc file:
root_servers["."] = "131.161.247.232,"
root_servers["."] += "208.185.249.250,"
root_servers["."] += "66.227.42.140,"
root_servers["."] += "66.227.42.149,"
root_servers["."] += "65.243.92.254"
Note that there is no "+=" in the first line, and the last line does not have a comma at the end. Read the recursive tutorial document for more information.
No.
In more detail, MaraDNS does not use autoconf for the following reasons:
-
Autoconf is designed to solve a problem that existed in the mid 1990s but does not exist today: A large number of different incompatible C compilers and libc implementations. These days, most systems are using gcc as the compiler and some version of glibc as the libc. There is no longer a need, for example, to figure out whether a given implementation of
getopt()
allows '--
' options. MaraDNS's./configure
script can be run in only a second or two; compare this to the 3-5 minute process autoconf's./configure
needs. -
Autoconf leaves GPL-tained files in a program's build tree. MaraDNS is licensed under a BSD license that is not GPL-compatible, so MaraDNS can not be distributed with these GPL-licensed files.
This leads us to the next question:
build process?
To change the compiler used by MaraDNS:
-
Run the
./configure
script -
Open up the file
Makefile
with an editor -
Look for a line that starts with
CC
-
If there is no line that starts with
CC
, create one just before the line that starts withFLAGS
-
Change (or create) that line to look something like
CC=gcc296
In this example, the 2.96 version of gcc is used to compile MaraDNS. -
Note that it is important to not remove anything from this line you do not understand; doing so will make MaraDNS unable to compile or run. So, if the CC line looks like
CC=gcc $(LDFLAGS) -DNO_FLOCK
and you want to compile with gcc 2.96, change the line to look likeCC=gcc296 $(LDFLAGS) -DNO_FLOCK
retaining the flags added by the configuration script.
Changing compile-time flags is a similar process:
-
Run the
./configure
script -
Open up the file
Makefile
with an editor -
Look for a line that starts with
FLAGS
-
Change (or create) that line to look something like
FLAGS=-O3
In this example, MaraDNS is compiled with the -O3 option. -
Note that it is important to not remove anything from this line you do not understand; doing so will make MaraDNS unable to compile or run. So, if the FLAGS line looks like
FLAGS=-O2 -Wall -DSELECT_PROBLEM
and you want to compile at optimization level three, change this line to look likeFLAGS=-O2 -Wall -DSELECT_PROBLEM
retaining the flags added by the configuration script.-DSELECT_PROBLEM
for example, is needed in the Linux compile or MaraDNS will have problems with freezing up.
am using?
No.
There is, however, a CentOS 5-compatible RPM spec file in the build directory.
are not working.
Since Windows 32 does not have some features that *NIX OSes have, the native Windows port does not have all of the features of the *NIX version of MaraDNS. In particular, the following features are disabled:
-
ipv6 (this is actually a mingw32, not a Windows deficiency)
-
The
chroot_dir
mararc variable -
The
maradns_gid
andmaradns_uid
mararc variables -
The
maxprocs
mararc variable -
The
synth_soa_serial
variable can not have a value of 2 -
There is no DNS-over-TCP support
If any of the above features are desired, try compiling MaraDNS using
Cygwin. Note that the Cygwin port of MaraDNS does not have ipv6
support, and that while chroot_dir
works in Cygwin, it does not have
the security that the *NIX chroot() call has.
This is usually caused by a syntax error in one's mararc file, or by
another MaraDNS process already running. To see what is happening, look
at your system log (/var/log/messages
in Centos 3) to see what errors
MaraDNS reports. If you do not know how to look at a system log, you
can also invoke MaraDNS from the command line as root; any errors will
be visible when starting MaraDNS.
updating software is non-trivial.
Regularly updating software is required to keep something as complicated as a DNS server secure; there is not a DNS server out there so secure that it never needs to be updated.
Since MaraDNS is finished, updates usually only happen about once a year.
The last security bug which required a MaraDNS update was made before September 28, 2015.
NXDOMAINs/IPV6 resolution
This was a bug in MaraDNS 1.2 which has long since been fixed.
MaraDNS 1.2 had a bug where it did not correctly process zones without any "normal" records. Upgrade to MaraDNS 2.0.
registrar for .fr domains)
Because of an issue with AFNIC (who, annoyingly enough, check the RA bit when registering a domain), in order to register a domain with AFNIC using MaraDNS as your DNS server, the following steps need to be followed:
-
MaraDNS version 1.4 or 2.0 needs to be used; if you're using an older version of MaraDNS, upgrade.
-
It is necessary to have recursion disabled, if using MaraDNS 1.4, either by compiling MaraDNS without recursive support (./configure --authonly ; make), or by making sure MaraDNS does not have recursion enabled (by not having
recursive_acl
set in one's MaraDNS 1.4 mararc file)
If one wishes to both register domains with AFNIC and use MaraDNS 1.4 as a recursive DNS server, it is required to have the recursive server be a separate instance of MaraDNS on a separate IP. It is not possible to have the same DNS server both send DNS packets in a way that both makes AFNIC happy and allows recursive queries.
Note also: AFNIC gives warnings about reverse DNS lookups; more information about this issue can be found in the FAQ entry about reverse DNS mappings(question 7). In addition, AFNIC requires DNS-over-TCP to work; information on configuring MaraDNS to have this can be found in the DNS-over-TCP tutorial.
To have the subdomains be visible to MaraDNS 1.4 recursive nameservers, add the following to your mararc file:
recurse_delegation = 1
This issue should be fixed in MaraDNS 2.0.
Here's what happening: I have rewritten the recursive resolver for MaraDNS. The old code was always designed to be a placeholder until I wrote a new recursive resolver.
The new recursive resolver is called "Deadwood"; right now it's fully functional and part of MaraDNS 2.0. More information is here:
http://maradns.blogspot.com/search/label/Deadwood
http://maradns.samiam.org/deadwood/
Since the old recursive code is a bit difficult to maintain, and since I in the process of rewriting the recursive code, my rule is that I will only resolve security issues with MaraDNS 1.0's recursive resolver.
There was a known bug in MaraDNS 1.2.12 where, should a client ask for a non-existent record in all caps, MaraDNS 1.2.12 will return a NXDOMAIN instead of a "not there" reply. Upgrade to 2.0.
Deadwood can block up to about 20,000 domains. More details are in the Deadwood FAQ.
Yes.
MaraDNS supports both having stars at the beginning of records and the end of records. For example, to have anything.example.com. have the IP 10.1.2.3, add this line to the zone file for example.com:
*.example.com. A 10.1.2.3
To have stars at the end of records, csv2_default_zonefile
has to be
set. The mararc parameter bind_star_handling
affects how star records
are handled. More information is in the mararc man page.
applications like telnet.
Some *NIX command line networking applications, such as telnet and ssh, try to do either a reverse DNS lookup (IP-to-host name conversion) or an IPv6 lookup. This slows things down and sometimes causes the applications to not work at all.
For people who do not need IPv6 lookups, add the following line to one's mararc file to have MaraDNS respond to all IPv6 lookups with a bogus "not found" reply:
reject_aaaa = 1
If knowing the hostname a given IP has isn't important, these kinds of lookups can also be disabled:
reject_ptr = 1
This can be caused either by a poorly written anti-virus program reporting a false positive, or because a virus on your system has infected your copy of MaraDNS/Deadwood.
Please use GPGto verify that the file which your scanner reports having a virus in has not been altered. In addition, please scan the file with AVG (free for non-commercial use) to verify your virus scanner has not reported a false positive.
If you have verified the GPG signature of the program and AVG reports a virus, please let us know with a Github issue. Otherwise, please use a better virus scanner and make sure there are no viruses on your computer.
Please note that the mailing list is no longer used to handle MaraDNS support requests. Please file a Github issue at https://github.com/samboy/MaraDNS/issuesto file a MaraDNS bug report.
The procedure for subscribing to the mailing list is as follows:
-
Send an email to [email protected] with "Subscribe" as the subject, or an email to [email protected]
-
You will get an email from [email protected] asking you to confirm your subscription. This can be done by replying to the message, or, more simply, by clicking on the link in the message.
-
Once you click on that link, click on the button marked "subscribe to list list"
-
You will now get a message stating 'Welcome to the "list" mailing list'.
-
Note that the mailing list is moderated and only relevant MaraDNS announcements are approved. People who need help should read the manualsor search the MaraDNS webpagefor support.
If you get an email from [email protected] with the subject "The results of your email commands", you did not correctly send an email to [email protected] with the subject "Subscribe".
If you do not get the email from [email protected] asking you for a confirmation, ensure that this email is not in your "spam" or "junk mail" folder. If you are unable to get these emails at your email address, please get a gmail email account, which can successfully subscribe to the MaraDNS mailing list. Note that subscription confirmation emails may be in Gmail's "promotions" tab.
MaraDNS 2 (both the authoritative maradns server and the recursive Deadwood server) responds to EDNS packets by ignoring the OPT record and acting as if it the packet did not have an OPT record.
MicroDNS(available in the tools/misc
directory of any MaraDNS 2
release) responds to EDNS queries the same way Deadwood 2.9.03 did: By
giving back "NOTIMPL" instead of answering the query with the default
IP. NanoDNS, in the interest of minimizing code side, responds to EDNS
requests by returning NOTIMPL in the header, giving the OPT query in
the AN section of the response, and giving the default IP in the AR
section of the DNS reply packet.
There are three ways to have MaraDNS always give the same IP in reply to any DNS query given to it:
-
The best way to do this is to set up a default zonefilethat causes any and all A queries to always give the IP (and also allows all AAAA queries to always give out the same IP6, all SPF or TXT queries to give out the same SPF record, etc.).
-
Another possibility, if someone just wants a simple DNS server that always gives out the same IP address to any and all DNS queries, is to use the MicroDNS program, available in
tools/misc
, as well as having its own web page. -
If MicroDNS is too bloated, there is also NanoDNS, which I will include the source code of below:
#include <arpa/inet.h>
#include <string.h>
#include <stdint.h>
#define Z struct sockaddr
#define Y sizeof(d)
int main(int a,char **b){uint32_t i;char q[512]
,p[17]="\xc0\f\0\x01\0\x01\0\0\0\0\0\x04";if(a>
1){struct sockaddr_in d;socklen_t f=511;bzero(&
d,Y);a=socket(AF_INET,SOCK_DGRAM,0);*((uint32_t
*)(p+12))=inet_addr(b[1]);d.sin_family=AF_INET;
d.sin_port=htons(53);bind(a,(Z*)&d,Y);for(;;){i
=recvfrom(a,q,255,0,(Z*)&d,&f);if(i>9&&q[2]>=0)
{q[2]|=128;q[11]?q[3]|=4:1;q[7]++;memcpy(q+i,p,
16);sendto(a,q,i+16,0,(Z*)&d,Y);}}}return 0;}
NanoDNS takes one argument: The IP we return. This program binds
to all IP addresses a given machine has on the UDP DNS port (port 53).
For example, to make a DNS server that binds to all IPs your system has
and return the IP 10.11.12.13 to any UDP DNS queries sent to it,
compile the above C program, call it NanoDNS
, and invoke it with
NanoDNS 10.11.12.13
Note that NanoDNS does not daemonize, nor log
anything, nor have any other space-wasting features.
I have changed MaraDNS' tagline from "MaraDNS: A security-aware DNS server" to "MaraDNS: A small open-source DNS server" because MaraDNS does not support DNSSEC. I have blogged about this:
http://samiam.org/blog/20120326.html
denial-of-service attack?
While I do not have time to implement rate limiting, CentOS 6 does support response rate limiting at the firewall level. The following iptables commands allow a given IP to only send MaraDNS/Deadwood 20 DNS queries every four seconds:
iptables -A INPUT -p udp --dport 53 -m state --state NEW -m recent --set --name DDOS --rsource
iptables -A INPUT -p udp --dport 53 -m state --state NEW -m recent --update --seconds 4 --hitcount 20 --name DDOS --rsource -j DROP
To verify they are applied:
iptables --list
To save these commands in CentOS so they are applied at system boot time:
iptables-save > /etc/sysconfig/iptables
Disclaimer
These incantations work in CentOS 6 but may or may not work in other versions of Linux. I do not support non-CentOS6 Linux installs of MaraDNS.
For people who want DNS-over-TCP, instructions are in the DNS-over-TCP tutorial. Note that Windows users will have to use Cygwin to have DNS-over-TCP.
However, DNS-over-TCP is not necessary. DNS-over-TCP is optional as per section 6.1.3.2 of RFC1123; any program or web service that considers no DNS-over-TCP an error is not RFC-compliant.
Not having DNS-over-TCP is more secure, because it gives attackers a smaller surface to attack.
While I like systemd, it is not part of CentOS 6 nor, obviously, Windows 7. That in mind, I have no plans to support systemd until 2017, when I plan to update MaraDNS' supported operating systems.
However, Tomasz Torcz has kindly made some systemd files for MaraDNS, which people are free to use.
As an aside, I do not like the fact that Debian will probably not make systemd the default init; I do not think this kind of fragmentation is good for Linux.
IP_FREEBIND is a non-POSIX Linux-specific extension to POSIX's netinet/in.h, and, as such, has no place in MaraDNS' code. MaraDNS strives to use POSIX-compliant calls so that it can compile on as many systems as possible.
When I say that Windows 7 and CentOS 6 are the only supported operating systems for MaraDNS, this does not mean that MaraDNS will not compile and run on other systems; it merely means that I can not provide support for Github bug reportsfor people who want to run MaraDNS in Minix, one of the open-source BSD variants, or what not.
The Kloxo-MRcontrol panel has MaraDNS support.
It means to not forget the tailing dot.
Hostnames in zone files need to be properly terminated; if a hostname is in the form “foo.example.com”, this name will not parse and return an error with a note to not forget the trailing dot.
To fix this, put a trailing dot at the end of the hostname, so it looks like “foo.example.com.” (observe that dot at the end) instead of “foo.example.com”
MaraDNS does not impose any limitations on the top level domain used in zone files and other places, as is fully compatible with newer top level domains like “today.”
Note that, if using an internationalized domain name, it needs to be translated in to Punycode first. For example, if using the domain name “ñ.com.”, it needs to be in the form “xn--ida.com.” in MaraDNS’ mararc and zone files.
Yes, but the internationalized domain name (IDN) needs to be translated in to Punycode first. For example, if using the domain name “ñ.com.”, it needs to be in the form “xn--ida.com.” in MaraDNS’ mararc and zone files.
In the unusual case of having a csv2 zone file with Macintosh-style newlines (as opposed to DOS or UNIX newlines), while the file will parse, any errors in the file will be reported as being on line 1.
The system startup script included with MaraDNS assumes that the only MaraDNS processes running are started by the script; it stops all MaraDNS processes running on the server when asked to stop MaraDNS.
MaraDNS needs to use the zoneserver program to serve DNS records over TCP. See zoneserver(8) for usage information.
MaraDNS does not use the zone file ("master file") format specified in chapter 5 of RFC1035.
MaraDNS default behavior with star records is not RFC-compliant. In
more detail, if a wildcard MX record exists in the form
".example.com", and there is an A record for "www.example.com", but no
MX record for "www.example.com", the correct behavior (based on RFC1034
§4.3.3) is to return "no host" (nothing in the answer section, SOA in
the authority section, 0 result code) for a MX request to
"www.example.com". Instead, MaraDNS returns the MX record attached to
".example.com". This can be changed by setting bind_star_handling
to
1.
Star records (what RFC1034 calls "wildcards") can not be attached to NS records.
MaraDNS, like every other known DNS implementation, only supports a QDCOUNT of 0 or 1.
These are features which I do not plan to implement in MaraDNS.
MaraDNS does not have a disk-based caching scheme for authoritative zones.
MaraDNS' UDP server only loads zone files while MaraDNS is first started. UDP Zone information can only be updated by stopping MaraDNS, and restarting MaraDNS again. Note that TCP zone files are loaded from the filesystem at the time the client requests a zone.
MaraDNS does not have support for allowing given host names to only resolve for a limited range of IPs querying the DNS server, or for host names to resolve differently, depending on the IP querying the host name.
MaraDNS only allows wildcards at the beginning or end of a host name. E.g. names with wildcards like "foo..example.com". "www." will work, however, if a default zonefile is set up. Likewise, MaraDNS does not have regular expression hostname substitution.
MaraDNS does not have support for MRTG or any other SNMP-based logging mechanism.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Sam Trenholme (http://www.samiam.org) is responsible for this man page.
MaraDNS is written by me, Sam Trenholme, with a little help from my friends. Naturally, all errors in MaraDNS are my own (but read the disclaimer above).
Here is a partial list of people who have provided assistance:
Floh has generously set up a FreeBSD 4, FreeBSD 6, and Mac OS X system so that I can port MaraDNS to more platforms.
Albert Lee has provided countless bug reports, and, nicely enough, patches to fix said bugs. He has also made improvements to the code in the tcp "zoneserver".
Franky Van Liedekerke has provided much invaluable assistance. As just one example, he provided invaluable assistance in getting MaraDNS to compile on Solaris. In addition, he has provided much valuable SQA help.
Christian Kurz, who has provided invaluable bug reports, especially when I had to re-implement the core hashing algorithm.
Remmy, who is providing both the web space and a mailing list for maradns.org.
Phil Homewood, who provided invaluable assistance with finding and fixing bugs in the authoritative portion of the MaraDNS server. He helped me plug memory leaks, find uninitialized variables being used, and found a number of bugs I was unable to find.
Albert Prats kindly provided Spanish translations for various text files.
Shin Zukeran provided a patch to recursive.c which properly makes a normal null-terminated string from a js_string object, to send as an argument to open() so we can get the rijndael key for the PRNG.
D Richard Felker III has provided invaluable bug reports. By looking at his bug reports, I have been able to hunt down and fix many problems that the recursive nameserver had, in addition to at least one problem with the authoritative nameserver.
Ole Tange has also given me many valuable MaraDNS bug reports.
Florin Iucha provided a tip in the FAQ for how to compile MaraDNS on OpenBSD.
Roy Arends (one of the BIND developers, as it turns out) found a serious security problem with MaraDNS, where MaraDNS would answer answers, and pointed it out to me.
Code used as the basis for the psudo-random-number generator was written by Vincent Rijmen, Antoon Bosselaers, and Paulo Barreto. I appreciate these programmers making the code public domain, which is the only license under which I can add code to MaraDNS under.
Ross Johnson and others have made a Win32 port of the Pthreads library; this has made a native win32 port of MaraDNS possible.
I also appreciate the work of Dr. Brian Gladman and Fritz Schneider, who have both written independent implementations of AES from which I obtained test vectors. With the help of their hard work, I was able to discover a subtle security problem that previous releases of MaraDNS had.
mararc - Format of the mararc zone file that MaraDNS uses
Mararc files use a syntax that is a subset of Python 2.2.3 syntax. In particular, Python 2.2.3 (and possibly other versions of Python) can read a properly formatted mararc file without error.
Unlike Python, however, a mararc file can only use certain variable names, and the variables can only be declared as described below.
Comments (lines ignored by the MaraDNS parser) start with the '#' character, like this:
# This is a comment
The MaraDNS parser also ignores lines which contain only white space.
The MaraRC file supports two operators: = and +=
The = operator can be used to assign both numeric and string values
The += operator can only be used on string values, and concatenates the value to the right of the += operator to the string specified to the left of the += operator.
Examples:
ipv4_bind_addresses = "10.2.19.83"
ipv4_bind_addresses += ",10.2.66.74"
ipv4_bind_addresses += ",10.3.87.13"
ipv4_bind_addresses now has the value "10.2.19.83,10.2.66.74,10.3.87.13"
ipv4_alias["icann"] = "198.41.0.4"
ipv4_alias["icann"] += ",192.228.79.201"
ipv4_alias["icann"] += ",192.33.4.12,128.8.10.90"
Follows is a listing of variables that can be declared in the mararc file.
A dictionary variable is an array that can have multiple elements. Unlike a traditional array, these arrays are indexed by strings instead of numbers. These are analogous to associative arrays, or what Perl somewhat inaccurately calls hashes.
The syntax of a dictionary variable is in the following form:
name["index"] = "value"
Where name is the name of the dictionary variable, index is the index of the array, and value is the value stored at that index.
Every time we have a dictionary-type variable (such as csv2), we must first initialize it using a line in the following form:
csv2 = {}
Here, csv2 is the name of the "dictionary" variable that we are initializing.
Here is a listing of all "dictionary"-style variables that MaraDNS uses:
The csv2 dictionary variable stores all of the zone names and file names for the zone files that MaraDNS uses. Note that csv2 files are read after MaraDNS is chrooted. Hence the filename is relative to the chroot_dir. Example:
csv2["example.net."] = "db.example.net"
See csv2(5) for a description of this file's format.
The dictionary index (zone name) can not have a * in it. If it does, MaraDNS will terminate with an "Illegal zone name" error.
Please note that, in order to reload a zone file, it is necessary to restart MaraDNS and reload all zone files. MaraDNS uses a hash data format which loads records very quickly from memory, but requires a restart to update.
csv1: Used to indicate the filename to use for a given zone stored in the legacy csv1 zone file format. This is primarily for compatibility with people who have maradns-1.0 zone files.
csv1["zone"] = "filename"
csv1: A pipe-separated-file. See csv1(5).
zone: the zone that file in question is authoritative for
filename: the file with the CSV1 zone data
Note that csv1 files are read after MaraDNS is chrooted, and, hence the filename is relative to the chroot_dir.
See the csv1(5) man page for more information on this file format.
ipv4_alias: Used to give nicknames or aliases for ip/netmask pairs for ipv4 (standard 32-bit) IP addresses.
ipv4_alias["name"] = "ip1/netmask,ip2/netmask,etc"
name: The name of the alias in question
ip: The ip portion of an ip/netmask pair
netmask: the mask portion of an ip/netmask pair
,: Used to separate ip/netmask pairs. Spaces may be placed before or after this comma.
An ip is in dotted-decimal format, e.g. "10.1.2.3".
The netmask can be in one of two formats: A single number between 1 and 32, which indicates the number of leading "1" bits in the netmask, or a 4-digit dotted-decimal netmask.
The netmask is used to specify a range of IPs.
10.1.1.1/24 indicates that any ip from 10.1.1.0 to 10.1.1.255 will match.
10.1.1.1/255.255.255.0 is identical to 10.1.1.1/24
10.2.3.4/16 indicates that any ip from 10.2.0.0 to 10.2.255.255 will match.
10.2.3.4/255.255.0.0 is identical to 10.2.3.4/16
127.0.0.0/8 indicates that any ip with "127" as the first octet (number) will match.
127.0.0.0/255.0.0.0 is identical to 127.0.0.0/8
The netmask is optional, and, if not present, indicates that only a single IP will "match". e.g:
10.9.9.9/32, 10.9.9.9/255.255.255.255, and 10.9.9.9 are all functionally identical, and indicate that only the ip 10.9.9.9 will match.
The significance of "match" depends on what we use the ipv4 alias for.
ipv4 aliases can nest. E.g:
ipv4_alias["susan"] = "10.6.7.8/24"
ipv4_alias["office"] = "susan,10.9.9.9"
Where "susan" in the "office" alias matches the value of the ipv4_alias susan.
Multiple levels of nesting are allowed. Self-referring nests will result in an error.
Normal variables. These are variables that can only take a single value.
The syntax of a normal variable is in the form
name = "value"
Where name is the name of the normal variable, and value is the value of the variable in question.
Here is a listing of normal variables that MaraDNS uses:
ipv4_bind_addresses: The IP addresses to give the MaraDNS server.
This accepts one or more ipv4 IPs in dotted-decimal (e.g. "127.0.0.1") notation, and specifies what IP addresses the MaraDNS server will listen on. Multiple bind addresses are separated with a comma, like this: "10.1.2.3, 10.1.2.4, 127.0.0.1"
This is a list of ip/netmask pairs that are allowed to get certain administrative information about MaraDNS, including:
-
The version number of MaraDNS running
-
The number of threads MaraDNS has
-
MaraDNS' internal timestamp value
Note that this information is not available unless the mararc variable debug_msg_level is sufficiently high. See the information on debug_msg_level below for details on this and on the TXT queries sent to get the above information.
bind_address: The IP address to give the MaraDNS server.
This accepts a single IP in dotted-decimal (e.g. "127.0.0.1") notation, and specifies what IP address the MaraDNS server will listen on. Note that ipv4_bind_addresses has the same functionality. This name is included so that old MaraDNS configuration files will continue to work with new MaraDNS releases.
In the case where there is both a star record for a given name and recordtype, a non-star record with the same name but a different recordtype, and no record for the given name and recordtype, MaraDNS will usually return the star record. BIND, on the other hand, will return a "not there" reply. In other words:
-
If a non-A record for
foo.example.com
exists -
An A record for
*.example.com
exists -
No A record for
foo.example.com
exists -
And the user asks for the A record for
foo.example.com
-
MaraDNS will usually return the A record attached to
*.example.com
-
BIND, on the other hand, returns a "not there" for
foo.example.com
If the BIND behavior is desired, set bind_star_handling
to 1.
Otherwise, set this to 0. In MaraDNS 1.3, this has a default value of
1.
In addition, if there is a star record that could match any given record type, when bind_star_handling is 1, it makes sure that MaraDNS does not incorrectly return a NXDOMAIN (RFC 4074 section 4.2).
Also, if bind_star_handling has a value of 2, MaraDNS will handle the following case exactly as per section 4.3.3 of RFC1034:
-
If a record for
foo.example.com
exists -
An A record for
*.example.com
exists -
And the user asks for the A record for
bar.foo.example.com
-
MaraDNS will usually return the A record attached to
*.example.com
-
RFC1034 section 4.3.3 says one should return a NXDOMAIN.
MaraDNS will exit with a fatal error if bind_star_handling
has any
value besides 0, 1, or 2.
chroot_dir: The directory MaraDNS chroots to
This accepts a single value: The full path to the directory to use as a chroot jail.
Note that csv1 zone files are read after the chroot operation. Hence, the chroot jail needs to have any and all zone files that MaraDNS will load.
This is a special zone file that allows there to be stars at the end of hostnames. This file is similar to a normal csv2 zone file, but has the following features and limitations:
-
Stars are allowed at the end of hostnames
-
A SOA record is mandatory
-
NS records are mandatory
-
Neither CNAME, FQDN4, nor FQDN6 records are permitted in the zone file
-
Delegation NS records are not permitted in the zone file
-
Default zonefiles may not be transferred via zone transfer
-
Both recursion and default zonefiles may not be enabled at the same time
Sometimes the IP list of nameservers will be different than the nameservers one is bound to. This allows the synthetic nameserver list to have different IPs.
Note that this may act in an unexpected manner if routable and non-routable (localhost and RFC1918) addresses are combined; in particular, a list with both routable and non-routable addresses will discard the non-routable IP addresses, and a list with rfc1918 and localhost addresses will discard the localhost addresses.
How the csv2 zone file parser handles tildes (the ~ character) in csv2 zone files. This is a numeric record, with a possible value between 0 and 3 (four possible values). The way the csv2 parser acts at different csv2_tilde_handling levels:
-
- The csv2 parser behaves the same as it does in old MaraDNS releases: The tilde has no special significance to the parser.
-
- A tilde is not allowed anywhere in a csv2 zone file.
-
- A tilde is only allowed between records in a csv2 zone file. If a tilde is between the first record and the second record, a tilde is required to be between all records. Otherwise, a tilde is not allowed anywhere in a csv2 zone file. The first record can not be a TXT, WKS, or LOC record.
-
- A tilde is required to be between all records in a csv2 zone file.
The default value for csv2_tilde_handling is 2; this allows compatibility with older zone files without tildes while allowing zone files to be updated to use the tilde to separate resource records.
This is a number indicating what level of information about a running MaraDNS process should be made public. When set to 0, no information will be made public.
When set to one (the default), or higher, a Tversion.maradns. (TXT query for "version.maradns.") query will return the version number of MaraDNS.
When set to two or higher, a Tnumthreads.maradns. (TXT query for "numthreads.maradns.") query will return the number of threads that MaraDNS is currently running, and a Tcache-elements.maradns. query will return the number of elements in MaraDNS' cache.
If MaraDNS is compiled with debugging information on, a Tmemusage.maradns. query will return the amount of memory MaraDNS has allocated. Note that the overhead for tracking memory usage is considerable and that compiling MaraDNS with "make debug" will greatly slow down MaraDNS. A debug build of MaraDNS is not recommended for production use.
When set to three or higher, a Ttimestamp.maradns. query will return, in seconds since the UNIX epoch, the timestamp for the system MaraDNS is running on.
This variable used to determine what kind of resource records were returned when an ANY query was sent. In MaraDNS, the data structures have since been revised to return any resource record type when an ANY query is sent; this variable does nothing, and is only here so that old MaraDNS mararc files will continue to work. The only accepted values for this variable were 3 and 15.
This is the port that MaraDNS listens on. This is usually 53 (the default value), but certain unusual MaraDNS setups (such as when resolving dangling CNAME records on but a single IP) may need to have a different value for this.
If this is set to a non-zero value, certain features of MaraDNS will be disabled in order to speed up MaraDNS' response time. This is designed for situations when a MaraDNS server is receiving a large number of queries, such as during a denial of service attack.
This is a numeric variable; its default value is zero, indicating that all of MaraDNS' normal features are enabled. Higher numeric values disable more features:
-
A dos_protection_level between 1 and 78 (inclusive) disables getting MaraDNS status information remotely.
-
A dos_protection_level of 8 or above disables CNAME lookups.
-
A dos_protection_level or 12 or above disables delegation NS records.
-
A dos_protection_level of 14 or above disables ANY record processing.
-
A dos_protection_level of 18 or above disables star record processing at the beginning of hostnames (default zonefiles still work, however).
-
A dos_protection_level of 78 disables all authoritative processing, including default zonefiles.
The default level of dos_protection_level is 0 when there are one or more zonefiles; 78 when there are no zone files.
If MaraDNS is compiled with as an authoritative server, then this variable will tell MaraDNS which ipv6 address for the UDP server to; for this variable to be set, MaraDNS must be bound to at least one ipv4 address.
If this is set to "YES", MaraDNS will not display the legal disclaimer when starting up.
This is a list of IPs which we will send UDP packets longer than the
512 bytes RFC1035 permits if necessary. This is designed to allow
zoneserver
, when used send regular DNS packets over TCP, to receive
packets with more data than can fit in a 512-byte DNS packet.
This variable only functions if MaraDNS is compiled as an authoritative only server.
maradns_uid: The numeric UID that MaraDNS will run as
This accepts a single numerical value: The UID to run MaraDNS as.
MaraDNS, as soon as possible drops root privileges, minimizing the damage a potential attacker can cause should there be a security problem with MaraDNS. This is the UID maradns becomes.
The default UID is 707.
maradns_gid: The numeric GID that MaraDNS will run as.
This accepts a single numerical value: The GID to run MaraDNS as.
The default GID is 707.
max_ar_chain: The maximum number of records to display if a record in the additional section (e.g., the IP of a NS server or the ip of a MX exchange) has more than one value.
This is similar to max_chain, but applies to records in the "additional" (or AR) section.
Due to limitations in the internal data structures that MaraDNS uses to store RRs, if this has a value besides one, round robin rotates of records are disabled.
The default value for this variable is 1.
max_chain: The maximum number of records to display in a chain of records.
With DNS, it is possible to have more than one RR for a given domain label. For example, "example.com" can have, as the A record, a list of multiple ip addresses.
This sets the maximum number of records MaraDNS will show for a single RR.
MaraDNS normally round-robin rotates records. Hence, all records for a given DNS label (e.g. "example.com.") will be visible, although not at the same time if there are more records than the value allowed with max_chain
The default value for this variable is 8.
max_tcp_procs: The (optional) maximum number of processes the zone server is allowed to run.
Sometimes, it is desirable to have a different number of maximum allowed tcp processes than maximum allowed threads. If this variable is not set, the maximum number of allowed tcp processes is "maxprocs".
max_total: The maximum number of records to show total for a given DNS request.
This is the maximum total number of records that MaraDNS will make available in a DNS reply.
The default value for this variable is 20.
max_mem is the maximum amount of memory we allow MaraDNS to allocate, in bytes.
The default value of this is to allocate 2 megabytes for MaraDNS' general use, and in addition, to allocate 3072 bytes for each element we can have in the cache or DNS record that we are authoritatively serving.
min_visible_ttl: The minimum value that we will will show as the TTL (time to live) value for a resource record to other DNS servers and stub resolvers. In other words, this is the minimum value we will ask other DNS server to cache (keep in their memory) a DNS resource record.
The value is in seconds. The default value for this is 30; the minimum value this can have is 5.
As an aside, RFC1123 section 6.1.2.1 implies that zero-length TTL records should be passed on with a TTL of zero. This, unfortunately, breaks some stub resolvers (such as Mozilla's stub resolver).
remote_admin: Whether we allow verbose_level
to be changed after
MaraDNS is started.
If remote_admin
is set to 1, and admin_acl
is set, any and all IPs
listed in admin_acl
will be able to reset the value of
verbose_level
from any value between 0 and 9 via a TXT query in the
form of 5.verbose_level.maradns.
What this will do is set
verbose_query
to the value in the first digit of the query.
This is useful when wishing to temporarily increase the verbose_level
to find out why a given host name is not resolving, then decreasing
verbose_level
so as to minimize the size of MaraDNS' log.
If this is set to 1, MaraDNS will not allow ANY queries, sending a RFC8482 response if one is given to MaraDNS. If this is 0, ANY queries are allowed. Default value: 1
When a CSV2 zone file doesn't have a SOA record in it, MaraDNS generates a SOA record on the fly. This variable determines the host name for the "SOA origin" (which is called the MNAME in RFC1035); this is the host name of the DNS server which has the "master copy" of a given DNS zone's file.
This host name is in human-readable format without a trailing dot, e.g.:
synth_soa_origin = "ns1.example.com"
If this is not set, a synthetic SOA record will use the name of the zone for the SOA origin (MNAME) field.
This determines whether we strictly follow RFC1912 section 2.2 with SOA serial numbers. If this is set to 1 (the default value), we do not strictly follow RFC1912 section 2.2 (the serial is a number, based on the timestamp of the zone file, that is updated every six seconds), but this makes it so that a serial number is guaranteed to be automatically updated every time one edits a zone file.
If this is set to 2, the SOA serial number will be in YYYYMMDDHH format, where YYYY is the 4-digit year, MM is the 2-digit month, DD is the 2-digit day, and HH is the 2-digit hour of the time the zone file was last updated (GMT; localtime doesn't work in a chroot() environment). While this format is strictly RFC1912 compliant, the disadvantage is that more than one edit to a zone file in an hour will not update the serial number.
I strongly recommend, unless it is extremely important to have a DNS zone that generates no warnings when tested at dnsreport.com, to have this set to 1 (the default value). Having this set to 2 can result in updated zone files not being seen by slave DNS servers.
Note that synth_soa_serial can only have a value of 1 on the native Windows port.
On systems where time_t is 32-bit, MaraDNS will always act as if
synth_soa_serial
has a value of 1. This is to avoid having MaraDNS
use invalid time and date values starting in late January of 2038;
systems with a 32-bit time_t can very well have their underlying system
libraries with regards to dates and times no longer correctly function
come 2038.
This only applies to the zoneserver (general DNS-over-TCP) program.
This is a list of IPs which are allowed to connect to the zoneserver and send normal TCP DNS requests. The zoneserver will convert TCP DNS requests in to UDP DNS requests, and send the UDP request in question to the server specified in tcp_convert_server. Once it gets a reply from the UDP DNS server, it will convert the reply in to a TCP request and send the reply back to the original TCP client.
Whether the RD (recursion desired) flag is set or not when converting a TCP DNS request in to a UDP DNS request is determined by whether the TCP client is on the recursive_acl list. Since MaraDNS 2.0 does not have recursion, the maradns daemon ignores the RD bit (Deadwood will not process any queries without the RD bit set).
This only applies to the zoneserver (general DNS-over-TCP) program.
This is the UDP server which we send a query to when converting DNS TCP queries in to DNS UDP servers. Note that, while this value allows multiple IPs, all values except the first one are presently ignored.
timestamp_type: The type of timestamp to display. The main purpose of this option is to suppress the output of timestamps. Since duende uses syslog() to output data, and since syslog() adds its own timestamp, this option should be set to 5 when maradns is invoked with the duende tool.
This option also allows people who do not use the duende tool to view human-readable timestamps. This option only allows timestamps in GMT, due to issues with showing local times in a chroot() environment.
This can have the following values:
0
The string "Timestamp" followed by a UNIX timestamp
1
Just the bare UNIX timestamp
2
A GMT timestamp in the Spanish language
3
A (hopefully) local timestamp in the Spanish language
4
A timestamp using asctime(gmtime()); usually in the English
language
5
No timestamp whatsoever is shown (this is the best option when
maradns is invoked with the duende
tool).
6
ISO GMT timestamp is shown
7
ISO local timestamp is shown
On systems where time_t is 32-bit, MaraDNS will always act as if
timestamp_type
has a value of 5, never showing a timestamp. This is
to avoid having MaraDNS show an invalid timestamp starting in late
January of 2038; systems with a 32-bit time_t can very well have their
underlying system libraries with regards to dates and times no longer
correctly function come 2038.
The default value for this variable is 5.
verbose_level: The number of messages we log to stdout
This can have five values:
0
No messages except for the legal disclaimer and fatal parsing
errors
1
Only startup messages logged (Default level)
2
Error queries logged
3
All queries logged
4
All actions adding and removing records from the cache logged
The default value for this variable is 1.
zone_transfer_acl: List of ips allowed to perform zone transfers with the zone server
The format of this string is identical to the format of an ipv4_alias entry.
# Example mararc file (unabridged version)
# The various zones we support
# We must initialize the csv2 hash, or MaraDNS will be unable to
# load any csv2 zone files
csv2 = {}
# This is just to show the format of the file
#csv2["example.com."] = "db.example.com"
# The address this DNS server runs on. If you want to bind
# to multiple addresses, separate them with a comma like this:
# "10.1.2.3,10.1.2.4,127.0.0.1"
ipv4_bind_addresses = "127.0.0.1"
# The directory with all of the zone files
chroot_dir = "/etc/maradns"
# The numeric UID MaraDNS will run as
maradns_uid = 99
# The (optional) numeric GID MaraDNS will run as
# maradns_gid = 99
# Normally, MaraDNS has some MaraDNS-specific features, such as DDIP
# synthesizing, a special DNS query ("erre-con-erre-cigarro.maradns.org."
# with a TXT query returns the version of MaraDNS that a server is
# running), unique handling of multiple QDCOUNTs, etc. Some people
# might not like these features, so I have added a switch that lets
# a sys admin disable all these features. Just give "no_fingerprint"
# a value of one here, and MaraDNS should be more or less
# indistinguishable from a tinydns server.
no_fingerprint = 0
# These constants limit the number of records we will display, in order
# to help keep packets 512 bytes or smaller. This, combined with round_robin
# record rotation, help to use DNS as a crude load-balancer.
# The maximum number of records to display in a chain of records (list
# of records) for a given host name
max_chain = 8
# The maximum number of records to display in a list of records in the
# additional section of a query. If this is any value besides one,
# round robin rotation is disabled (due to limitations in the current
# data structure MaraDNS uses)
max_ar_chain = 1
# The maximum number of records to show total for a given question
max_total = 20
# The number of messages we log to stdout
# 0: No messages except for fatal parsing errors and the legal disclaimer
# 1: Only startup messages logged (default)
# 2: Error queries logged
# 3: All queries logged (but not very verbosely right now)
verbose_level = 1
# Here is a ACL which restricts who is allowed to perform zone transfer from
# the zoneserver program
# Simplest form: 10.1.1.1/24 (IP: 10.1.1.1, 24 left bits in IP need to match)
# and 10.100.100.100/255.255.255.224 (IP: 10.100.100.100, netmask
# 255.255.255.224) are allowed to connect to the zone server
# NOTE: The "maradns" program does not serve zones. Zones are served
# by the "zoneserver" program.
#zone_transfer_acl = "10.1.1.1/24, 10.100.100.100/255.255.255.224"
If one should declare the same the same index twice with a dictionary variable, MaraDNS will exit with a fatal error. This is because earlier versions of MaraDNS acted in a different manner than Python 2.3.3. With Python 2.3.3, the last declaration is used, while MaraDNS used to use the first declaration.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
zoneserver - handle zone transfers and other TCP functions for MaraDNS
zoneserver listens on port 53/tcp and handles DNS zone transfers and any DNS query done over TCP instead of UDP. zoneserver uses a configuration file, /etc/mararc by default, to determine its parameters.
zoneserver -f pointer_to_mararc_file
-f
Specifies the location of the configuration file. MaraDNS uses the
same configuration file for both the main dns server and the
zoneserver.
The file format for the mararc file can be found in the mararc(5) manual page. In particular, the zoneserver uses the zone_transfer_acl, tcp_convert_acl, tcp_convert_server, and bind_address mararc parameters.
In this example mararc file, which is used both by maradns and zoneserver, we allow 10.1.2.3, 10.1.14.7, and 192.168.116.{any} to transfer zones, and we allow anyone on the internet to perform TCP queries. The only zone served in this example is example.com:
ipv4_bind_addresses = "10.1.1.1" # Our IP
tcp_convert_server = "10.1.1.1" # IP of UDP DNS server
tcp_convert_acl = "0.0.0.0/0" # Anyone may do DNS-over-TCP
chroot_dir = "/etc/maradns" # Where zone files are
csv2 = {} # Initialize list of zone files
csv2["example.com."] = "db.example.com" # example.com zone file
# The next line is a list of who can transfer zones from us
zone_transfer_acl = "10.1.2.3, 10.1.14.7, 192,168.116.0/24"
The man pages maradns(8) and mararc(5)
zoneserver assumes that the authoritative NS records are immediately after the SOA record, and that there is at least one non-NS between that last authority NS record for the zone and the first delegation NS record.
IXFR requests are incremental zone transfers, meaning that the DNS server should only display records changed since the last IXFR request. zoneserver, however, treats an IXFR as if it were an AXFR request, outputting all of the records for the zone in question.
zoneserver closes the TCP connection after transferring the requested zone.
If an unauthorized client attempts to connect to the zoneserver, zoneserver immediately disconnects the unauthorized client.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MaraDNS is written by Sam Trenholme. Jaakko Niemi used 5 minutes to put the original version this manpage together. Sam has subsequently revised this manual page.