Skip to content

Latest commit

 

History

History
5945 lines (4319 loc) · 203 KB

REFERENCE.md

File metadata and controls

5945 lines (4319 loc) · 203 KB

MaraDNS reference manual

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 man page

NAME

Deadwood - A fully recursive caching DNS resolver

DESCRIPTION

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.

COMMAND LINE ARGUMENTS

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.

CONFIGURATION FILE FORMAT

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.

PARAMETER TYPES

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)

SUPPORTED PARAMETERS

The Deadwood configuration file supports the following parameters:

allow_block_hash_zero_key

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.

bind_address

This is the IP (or possibly IPv6) address we bind to.

blocked_hosts_hash_file

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

cache_file

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.

chroot_dir

This is the directory the program will run from.

deliver_all

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.

dns_port

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

filter_rfc1918

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

handle_noreply

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

handle_overload

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.

hash_magic_number

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.

ip4

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.

ip6

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" 

ip_blocklist

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.

maradns_uid

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.

maradns_gid

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.

max_ar_chain

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.

max_inflights

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.

max_ttl

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.

maximum_cache_elements

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.

maxprocs

This is the maximum number of pending remote UDP connections Deadwood can have. The default value for this is 1024.

max_tcp_procs

This is the number of allowed open TCP connections. Default value: 8

min_ttl

The minimum amount of time we will keep an entry in the cache, in seconds (also called "Minimum TTL").

num_retries

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

ns_glueless_type

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.

random_seed_file

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.

recurse_min_bind_port

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.

recurse_number_ports

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.

recursive_acl

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.

reject_aaaa

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.

reject_mx

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).

reject_ptr

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.

resurrections

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

rfc8482

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.

root_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.

source_ip4

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.

tcp_listen

In order to enable DNS-over-TCP, this variable must be set and have a value of 1. Default value: 0

timeout_seconds

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.

timeout_seconds_tcp

How long to wait on an idle TCP connection before dropping it. The default value for this is 4, as in 4 seconds.

ttl_age

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.

upstream_port

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.

upstream_servers

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.

verbose_level

This determines how many messages are logged on standard output; larger values log more messages. The default value for this is 3.

ip/mask format of IPs

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

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.

Parsing other files

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.

IPV6 support

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 

SECURITY

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.

COMMENTS

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.

DAEMONIZATION

Deadwood does not have any built-in daemonization facilities; this is handled by the external program Duende or any other daemonizer.

Example configuration file

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 

BUGS

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.

LEGAL DISCLAIMER

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.

AUTHORS

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 man page

NAME

askmara - do simple dns queries

DESCRIPTION

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).

USAGE

askmara [-n] [ -v | -t timeout] query [ server ]

OPTIONS

-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.

EXAMPLES

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.

BUGS

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).

SEE ALSO

maradns(8) http://www.maradns.org

LEGAL DISCLAIMER

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.

AUTHOR

MaraDNS is written by Sam Trenholme. Jaakko Niemi used 5 minutes to roll this manpage together, which Sam has subsequently revised.

blockHashMake man page

NAME

blockHashMake - Make a block hash file for Deadwood

DESCRIPTION

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.

COMMAND LINE ARGUMENTS

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.

HOST LIST FORMAT

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.

LIMITATIONS

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.

LEGAL DISCLAIMERS

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.

AUTHORS

Sam Trenholme (https://www.samiam.org) is responsible for this program and man page.

blockHashRead man page

NAME

blockHashRead - Read a block hash file

DESCRIPTION

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.

USAGE

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.

HOST LIST FORMAT

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.

LIMITATIONS

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.

LEGAL DISCLAIMERS

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.

AUTHORS

Sam Trenholme (https://www.samiam.org) is responsible for this program and man page.

coLunacyDNS man page

NAME

coLunacyDNS - A DNS server configured by Lua

DESCRIPTION

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.

Getting started

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.

Configration file examples

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 

Security considerations

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.

Limitations

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.

The API available to the Lua script

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.

coDNS.solve

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.

Reading files

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.

processQuery

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).

Global settings

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).

Test coverage

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 man page

NAME

csv1 - Format of the csv1 zone file that MaraDNS uses

SPECIAL NOTE

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.

SPECIAL CHARACTERS

| 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.

NOTES ON PROCESSING

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.

RR FORMAT

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.

SUPPORTED RR TYPES

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
 

FORMAT OF SUPPORTED RR TYPES

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

 
# 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.% 
 

LEGAL DISCLAIMER

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.

AUTHOR

Sam Trenholme http://www.samiam.org/

csv2 man page

NAME

csv2 - Description of the csv2 zone file that MaraDNS uses

DESCRIPTION

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.

Tilde delimitation

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.

Resource record format

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:

A

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 ~ 

PTR

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. ~ 

MX

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 ~ 

AAAA

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 ~ 

SRV

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.% ~ 

NAPTR

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.

NS

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. ~ 

SOA

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@x.org. 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\.doe@x.org. 1 7200 3600 604800 1800 ~ 

Note that the csv2 parser will not allow more than one dot in a row; 'john..doe@x.org' 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@x.org. /serial 7200 3600 604800 1800 ~ 

The '/serial' string is case-sensitive; only '/serial' in all lower case will parse.

TXT

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.

SPF

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.

RAW

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.

FQDN4

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.

FQDN6

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.

CNAME

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.

Historical and uncommon resource records

The following resource records are mainly of historical interest, or are not commonly used.

HINFO

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

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

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. ~ 

MB, MG, MINFO, and MR

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 mg@example.net. ~ 
example.net. MINFO rm@example.net. re@example.net. ~ 
example.net. MR mr@example.net. ~ 

More information about these records can be found in RFC1035.

AFSDB, RP, X25, ISDN, and RT

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 rp@example.net. rp.example.net. ~ 
example.net. RP rp2@example.net. . ~ 
example.net. X25 311061700956 ~ 
example.net. ISDN 150862028003217 ~ 
example.net. ISDN 150862028003217;004 ~ 
example.net. RT 10 relay.example.net. ~ 

NSAP and NSAP-PTR

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. ~ 

PX

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. ~ 

GPOS

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.

LOC

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 ~ 

CAA

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' ~ 

STAR RECORDS

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.

PERCENT SYMBOL

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.

SLASH COMMANDS

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:

Default TTL

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 ~ 

Origin

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 

Opush and Opop

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.

Read

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 ~ 

EXAMPLE ZONE FILE

 
## 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' ~

LEGAL DISCLAIMER

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.

AUTHOR

Sam Trenholme http://www.samiam.org/

csv2_txt man page

NAME

csv2_txt - Description of txt and raw resource records in the csv2 zone file

DESCRIPTION

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).

ASCII AND UTF-8 DATA

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.

UNQUOTED DATA

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.

BACKSLASH ESCAPE SEQUENCES

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 

MULTI-LINE AND COMMENTED RECORDS

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' ~ 

MULTIPLE TXT CHUNKS

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.

RAW RECORDS

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 RECORDS

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'  

LEGAL DISCLAIMER

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.

AUTHOR

Sam Trenholme http://www.samiam.org/

duende man page

NAME

duende - run a child process as a daemon

DESCRIPTION

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.

SYSTEMD

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.

USAGE

duende (--pid=/path/to/file) child_process [ all subsequent arguments passed on to child ]

DETAILS

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.

LOGGING

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.

EXAMPLES

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 

BUGS

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.

SEE ALSO

maradns(8), syslog(3) http://www.maradns.org

LEGAL DISCLAIMER

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.

AUTHOR

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 man page

NAME

fetchzone - get dns zone from server

DESCRIPTION

fetchzone transfers a user-specified dns zone from a zone server and displays it in csv2 format on the standard output.

USAGE

fetchzone zone_name zone_server_IP [query_class]

OPTIONS

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.

EXAMPLES

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 

BUGS

Fetchzone will not correctly output host names with utf-8 characters in them.

SEE ALSO

The man pages maradns(8) and csv2(5)

http://www.maradns.org

LEGAL DISCLAIMER

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.

AUTHOR

Sam Trenholme

getzone man page

NAME

getzone - get dns zone from server

DESCRIPTION

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.

USAGE

getzone zone_name zone_server_IP [query_class]

OPTIONS

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.

EXAMPLES

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 

SEE ALSO

The man pages maradns(8) and csv1(5)

http://www.maradns.org

LEGAL DISCLAIMER

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.

AUTHOR

MaraDNS is written by Sam Trenholme. Jaakko Niemi used 5 minutes to put this manpage together. Sam has subsequently made revisions to this manpage.

maradns man page

Erre con erre cigarro 
Erre con erre barril 
Rápido ruedan los carros 
En el ferrocarril 

NAME

maradns - DNS server

SYNOPSIS

maradns [ -v | -f mararc_file_location ]

TABLE OF CONTENTS

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 

DESCRIPTION

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

USAGE

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.

FIREWALL CONFIGURATION

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.

FREQUENTLY ASKED QUESTIONS

INDEX

  1. I'm using an older version of MaraDNS

  2. How do I try out MaraDNS?

  3. What license is MaraDNS released under?

  4. How do I report bugs in MaraDNS?

  5. Some of the postings to the mailing list do not talk about MaraDNS!

  6. How do I get off the mailing list?

  7. How do I set up reverse DNS on MaraDNS?

  8. I am on a slow network, and MaraDNS can not process recursive queries

  9. When I try to run MaraDNS, I get a cryptic error message.

  10. After I start MaraDNS, I can not see the process when I run netstat -na

  11. What string library does MaraDNS use?

  12. Why does MaraDNS use a multi-threaded model?

  13. I feel that XXX feature should be added to MaraDNS

  14. I feel that MaraDNS should use another documentation format

  15. Is there any process I need to follow to add a patch to MaraDNS?

  16. Can MaraDNS act as a primary nameserver?

  17. Can MaraDNS act as a secondary nameserver?

  18. What is the difference between an authoritative and a recursive DNS server?

  19. The getzone client isn't allowing me to add certain hostnames to my zone

  20. Is MaraDNS portable?

  21. Can I use MaraDNS in Windows?

  22. MaraDNS freezes up after being used for a while

  23. What kind of Python integration does MaraDNS have

  24. Doesn't "kvar" mean "four" in Esperanto?

  25. How scalable is MaraDNS?

  26. I am having problems setting upstream_servers

  27. Why doesn't the MaraDNS.org web page validate?

  28. How do MX records work?

  29. Does MaraDNS have support for SPF?

  30. I'm having problems resolving CNAMES I have set up.

  31. I have a NS delegation, and MaraDNS is doing strange things.

  32. I am transferring a zone from another server, but the NS records are these strange "synth-ip" records.

  33. Where is the root.hints file?

  34. Are there any plans to use autoconf to build MaraDNS?

  35. How do I change the compiler or compile-time flags with MaraDNS' build process?

  36. Will you make a package for the particular Linux distribution I am using?

  37. I am using the native Windows port of MaraDNS, and some features are not working.

  38. MaraDNS isn't starting up

  39. You make a lot of releases of MaraDNS; at our ISP/IT department, updating software is non-trivial.

  40. I have star records in my zones, and am having problems with NXDOMAINs/IPV6 resolution

  41. I have a zone with only SOA/NS records, and the zone is not working.

  42. I am having problems registering my domain with AFNIC (the registrar for .fr domains)

  43. I can't see the full answers for subdomains I have delegated

  44. MaraDNS 1 has a problem resolving a domain

  45. MaraDNS 1.2 has issues with NXDOMAINS and case sensitivity.

  46. Can MaraDNS offer protection from phishing and malicious sites?

  47. Does maradns support star (wildcard) records?

  48. I'm having problems using MaraDNS with some *NIX command line applications like telnet

  49. My virus scanner reports that MaraDNS or Deadwood has a virus

  50. I can not subscribe to the MaraDNS mailing list

  51. How does MaraDNS respond to EDNS (RFC2671) packets?

  52. How to I get MaraDNS to always give the same IP to all DNS queries?

  53. Why did you change MaraDNS' tagline?

  54. How do you stop MaraDNS from taking part in a distributed denial-of-service attack?

  55. What about DNS-over-TCP?

  56. How do I use MaraDNS with systemd?

  57. Why doesn't MaraDNS use IP_FREEBIND?

  58. Is there a web interface for MaraDNS?

  59. What does the message “don’t forget the trailing dot” mean?

  60. Does MaraDNS support newer top level domains?

  61. Can MaraDNS handle IDN domain names?

ANSWERS

1. I'm using an older version of MaraDNS

Upgrade to MaraDNS 2.0. Here is an upgrade guide.

MaraDNS 1 is no longer supported; support ended on June 21, 2015.

2. How do I try out MaraDNS?

Read the quick start guide, which is the file named 0QuickStart in the MaraDNS distribution.

3. What license is MaraDNS released under?

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:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. 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.

4. How do I report bugs in MaraDNS?

Post your bug report as a Github issue.

5. Some of the postings to the mailing list do not talk about MaraDNS!

As of September 2013, the mailing list has become moderated and only postings on the mailing list are relevant MaraDNS announcements.

6. How do I get off the mailing list?

Send an email to list-unsubscribe@maradns.org, or an email to list-request@maradns.org 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.

7. How do I set up reverse DNS on MaraDNS?

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.

8. I am on a slow network, and Deadwood can not process recursive queries

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.

9. When I try to run MaraDNS, I get a cryptic error message.

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.

10. After I start MaraDNS, I can not see the process when I run

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.

11. What string library does MaraDNS use?

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

12. Why does MaraDNS use a multi-threaded model?

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.

13. I feel that XXX feature should be added to MaraDNS

There are no plans to add new features to MaraDNS or Deadwood at this time.

14. I feel that MaraDNS should use another documentation format

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.

15. Is there any process I need to follow to add a patch to MaraDNS?

I no longer accept third party patches

16. Can MaraDNS act as a primary nameserver?

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.

17. Can MaraDNS act as a secondary nameserver?

Yes.

Please read the DNS slavedocument, which is part of the MaraDNS tutorial.

18. What is the difference between an authoritative and a recursive

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.

19. The fetchzone client isn't allowing me to add certain hostnames

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.

20. Is MaraDNS portable?

MaraDNS is developed in CentOS 6 and Windows 7. MaraDNS may or may not compile and run on other systems.

21. Can I use MaraDNS in Windows?

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.

22. MaraDNS freezes up after being used for a while

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.

23. What kind of Python integration does MaraDNS have

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.

24. Doesn't "kvar" mean "four" in Esperanto?

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.

25. How scalable is MaraDNS?

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.

26. I am having problems setting upstream_servers

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" 

27. Why doesn't the MaraDNS.org web page validate?

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.

28. How do MX records work?

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.

29. Does MaraDNS have support for SPF?

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'

30. I'm having problems resolving CNAMES I have set up.

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

31. I have a NS delegation, and MaraDNS is doing strange things.

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.

32. I am transferring a zone from another server, but the NS 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.  
hostmaster@example.net 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.  
hostmaster@example.net 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.

33. Where is the root.hints file?

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.

34. Are there any plans to use autoconf to build MaraDNS?

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:

35. How do I change the compiler or compile-time flags with MaraDNS'

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 with FLAGS

  • 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 like CC=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 like FLAGS=-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.

36. Will you make a package for the particular Linux distribution I

am using?

No.

There is, however, a CentOS 5-compatible RPM spec file in the build directory.

37. I am using the native Windows port of MaraDNS, and some features

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 and maradns_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.

38. MaraDNS isn't starting up

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.

39. You make a lot of releases of MaraDNS; at our ISP/IT department,

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.

40. I have star records in my zones, and am having problems with

NXDOMAINs/IPV6 resolution

This was a bug in MaraDNS 1.2 which has long since been fixed.

41. I have a zone with only SOA/NS records, and the zone is not working.

MaraDNS 1.2 had a bug where it did not correctly process zones without any "normal" records. Upgrade to MaraDNS 2.0.

42. I am having problems registering my domain with AFNIC (the

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.

43. I can't see the full answers for subdomains I have delegated

To have the subdomains be visible to MaraDNS 1.4 recursive nameservers, add the following to your mararc file:

recurse_delegation = 1

44. MaraDNS 1 has a problem resolving a domain

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.

45. MaraDNS 1.2 had issues with NXDOMAINS and case sensitivity.

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.

46. Can MaraDNS offer protection from phishing and malicious sites?

Deadwood can block up to about 20,000 domains. More details are in the Deadwood FAQ.

47. Does maradns support star (wildcard) records?

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.

48. I'm having problems using MaraDNS with some *NIX command line

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

49. My virus scanner reports that MaraDNS or Deadwood has a virus

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.

50. I can not subscribe to the MaraDNS mailing list

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 list-request@maradns.org with "Subscribe" as the subject, or an email to list-subscribe@maradns.org

  • You will get an email from list-request@maradns.org 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 list-request@maradns.org with the subject "The results of your email commands", you did not correctly send an email to list-request@maradns.org with the subject "Subscribe".

If you do not get the email from list-request@maradns.org 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.

51. How does MaraDNS respond to EDNS (RFC2671) packets?

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.

52. How to I get MaraDNS to always give the same IP to all DNS queries?

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.

Why did you change MaraDNS' tagline?

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

How do you stop MaraDNS from taking part in a distributed

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.

What about DNS-over-TCP?

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.

How do I use MaraDNS with systemd?

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.

Why doesn't MaraDNS use IP_FREEBIND?

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.

Is there a web interface for MaraDNS?

The Kloxo-MRcontrol panel has MaraDNS support.

What does the message “don’t forget the trailing dot” mean?

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”

Does MaraDNS support newer top level domains?

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.

Can MaraDNS handle IDN domain names?

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.

BUGS

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.

UNIMPLEMENTED FEATURES

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.

LEGAL DISCLAIMER

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.

AUTHORS

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 man page

NAME

mararc - Format of the mararc zone file that MaraDNS uses

MARARC FILE FORMAT

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

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.

OPERATORS

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" 

MARARC VARIABLES

Follows is a listing of variables that can be declared in the mararc file.

DICTIONARY VARIABLE FORMAT

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.

DICTIONARY VARIABLES

Here is a listing of all "dictionary"-style variables that MaraDNS uses:

csv2

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

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

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.

ipv4_alias examples

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 VARIABLE FORMAT

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.

NORMAL VARIABLES

Here is a listing of normal variables that MaraDNS uses:

ipv4_bind_addresses

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"

admin_acl

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

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.

bind_star_handling

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

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.

csv2_default_zonefile

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

csv2_synthip_list

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.

csv2_tilde_handling

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:

    1. The csv2 parser behaves the same as it does in old MaraDNS releases: The tilde has no special significance to the parser.
    1. A tilde is not allowed anywhere in a csv2 zone file.
    1. 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.
    1. 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.

debug_msg_level

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.

default_rrany_set

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.

dns_port

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.

dos_protection_level

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.

ipv6_bind_address

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.

hide_disclaimer

If this is set to "YES", MaraDNS will not display the legal disclaimer when starting up.

long_packet_ipv4

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

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

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

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

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

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

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

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

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

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.

rfc8482

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

synth_soa_origin

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.

synth_soa_serial

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.

tcp_convert_acl

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).

tcp_convert_server

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

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

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

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

 
# 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" 
 

BUGS

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.

LEGAL DISCLAIMER

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 man page

NAME

zoneserver - handle zone transfers and other TCP functions for MaraDNS

DESCRIPTION

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.

USAGE

zoneserver -f pointer_to_mararc_file

OPTIONS

-f Specifies the location of the configuration file. MaraDNS uses the same configuration file for both the main dns server and the zoneserver.

CONFIGURATION FILE FORMAT

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.

EXAMPLE MARARC FILE

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" 

SEE ALSO

The man pages maradns(8) and mararc(5)

http://www.maradns.org

BUGS

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.

LEGAL DISCLAIMER

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.

AUTHOR

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.