💾 Archived View for going-flying.com › ~mernisse › 21.gmi captured on 2023-01-29 at 15:58:20. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
It's pretty obvious why running your own resolver is something worth doing, the privacy, security and performance advantages versus using someone else's DNS resolver is obvious. Now that we're going to talk about serving our own authoritative domains we should probably answer the question as to why you should care? There are two reasons, the easiest and most obvious is to provide DNS for services you are putting on the Internet, after all no one will be able to find your domain if you don't serve it.
Lets think about setting up a hypothetical, example domain, it will ultimately serve a Gemini capsule and accept mail. The first thing you will want to do is setup at least two servers, preferably on different providers, with static IP (and preferably IPv6) addresses. These can do other things as well, but in my case my second server is just a $5/month droplet on Digital Ocean. Once you have BIND installed you just need to tell it that it is going to answer questions about your domain. I am going to show examples based on Debian Linux because that's what I like. You can adjust for which ever distribution you prefer. Often the named(8) manpage will tell you where the default configuration files are.
To tell BIND that we are going to answer questions for our hypothetical going-flying.com domain we add the following to named.conf.local on our primary server.
zone "going-flying.com" IN { type master; notify yes; file "going-flying.com"; allow-update { none; }; allow-transfer { peers; }; };
On the rest of our servers we will add a slightly different stanza.
zone "going-flying.com" IN { type slave; masters { ip.address.of.primary; }; };
Also in named.conf.local on all of your servers you should make an ACL to prevent just any random host on the Internet from being able to download your entire zone.
acl peers { ip.address.of.each.server; can.also.be.a.network/cidr; also:takes:v6:prefixes/cidr; };
You should also probably setup TSIG authentication for your servers but I'll leave that as an advanced exercise for the reader. It's not that difficult and BIND provides a utility (dnssec-keygen) to generate the keys needed.
This is your actual zonefile. There are many many many more record types than what I will list in this simple example but these are enough to get your first zone online.
$TTL 21600 @ IN SOA ns01.ub3rgeek.net. hostmaster.ub3rgeek.net. ( 2021030200 ; serial 3600 ; refresh (1 hour) 1800 ; retry (30 mins) 1209600 ; expire (2 weeks) 21600 ; minimum (6 hrs) ) A 69.55.65.182 AAAA 2606:c380:c001:3::2 NS ns01.ub3rgeek.net. NS ns02.ub3rgeek.net.
This is the top of my zonefile. The first line specifies the default TTL for negative caching. You can read more about that in RFC-2308, but in a nutshell it is how long a client will cache the fact that there is no answer for the question. In the above case if we asked the server where we should send mail for going-flying.com the answer would be NXDOMAIN. This answer would be cached for 21600 seconds because of the $TTL line.
RFC-2308: Negative Caching of DNS Queries (DNS NCACHE)
Next we have RR or resource records. The format of the RR is a bit flexible since most of the fields have defaults that will be used if not specified.
Name | TTL | Class | Type | Data
Name can be thought of as the 'question' part of the RR. If I am asking for 'www.going-flying.com.' then BIND is trying to match on the Name field of the zone. Name can be specified as either a bare name or as a fully-qualified domain name. In the case of a bare name BIND with append the zone we are configuring to it automatically. To specify a FQDN you need to use the full name which includes the trailing '.'. In our example 'www' and 'www.going-flying.com.' refer to the same name.
The TTL and class are almost always omitted. If the TTL is omitted then the value of the default TTL is used (more on this later). Class is always IN. There are other classes but IN is Internet and that is the default.
Now we have the meat of the RR, the type. Each DNS question has a type associated with it. The most commonly used are the A and AAAA which map from a name to an IP (or IPv6) address.
Finally we have the data. This is the answer to the question. The format of the answer depends on the type of the RR. Looking back at our example zone file after the $TTL line we have a special RR that uses the @ name. This RR is of type SOA which means Start of Authority. This defines the metadata associated with the zone. @ is a special name that resolves to the zone that we are configuring. The SOA data starts with the primary DNS server that is serving the domain, then the admin e-mail address (with the @ replaced with a .) then a set of values in parenthesis. The values in the parenthesis are as follows
Serial Number | Refresh Interval | Retry Interval | Expire | Minimum TTL
The serial number can be anything, but it MUST increment. A secondary server will not download a new zonefile from the primary server if the serial number is less than or equal to what it already has. Getting this wrong can cause all sorts of problems with your servers falling out of sync. The rule of thumb (for as long as I have been doing this, so c. 1997) has been to use YYYYMMDDHHMM## as a format, so the 3rd update on 2021-03-19 would have a serial of 2021031902 (note the zero index). The TTL time in the SOA is the default TTL used on any other RR if it is omitted. The Refresh, Retry and Expire times are all used by the secondary servers to determine how often they check in to see if there are updates. Note that the 'notify yes' line in the named.conf.local file earlier will cause the primary DNS server to tell the secondary server when it updates are available. RIPE has provided some guidance on reasonable defaults for these values. The example contains the values that I use on my production domains.
Recommendations for DNS SOA Values
After the SOA we have the A and AAAA records that I talked about. Because we specified @ before BIND assumes we are still talking about the same name. It will continue to assume that until we specify a new name. After the A and AAAA records we ourselves the NS records. Here we list the names of all the DNS servers that are serving our zone. Note that we could use the short names or the FQDNs here. In my case my DNS servers serve several domains so I just refer to them by FQDN here.
Finally we are going to add one last RR type so we can receive mail on our going-flying.com domain.
MX 10 mail.provider.com.
This 'MX' record stands for 'mail exchanger' and was created to allow mail servers to discover the proper server (or servers) when presented with an e-mail address to deliver to. A mail server will look for an MX record first and if it doesn't find it may try to connect to the IP address for the domain (if there is an A or AAAA record for the root of the zone). The format of the data part of this RR type is as follows.
Preference | Exchange
Domain Implementation and Specification
A "Null MX" No Service Resource Record for Domains That Accept No Mail
The preference is a 16 bit integer which provides a preference for the server. The exchange is the name of the server. A mail sever should work their way though the list of available exchangers starting with the lowest preference number first. Any exchangers with the same preference number should be tried round-robin.
Once you have this up and running you should be able to query your server and get back an authoritative answer for your domain.
; <<>> DiG 9.11.5-P4-5.1+deb10u3-Debian <<>> soa going-flying.com @ns01.ub3rgeek.net ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14819 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 5 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ; COOKIE: 085f3ba17163fef87b9206a260553dd380c61eb48d9fc0f9 (good) ;; QUESTION SECTION: ;going-flying.com. IN SOA ;; ANSWER SECTION: going-flying.com. 21600 IN SOA ns01.ub3rgeek.net. hostmaster.ub3rgeek.net. 2021030200 3600 1800 1209600 21600 ;; AUTHORITY SECTION: going-flying.com. 21600 IN NS ns01.ub3rgeek.net. going-flying.com. 21600 IN NS ns02.ub3rgeek.net. ;; ADDITIONAL SECTION: ns01.ub3rgeek.net. 21600 IN AAAA 2606:c380:c001:3::3 ns02.ub3rgeek.net. 21600 IN AAAA 2604:a880:1:20::5ff:7001 ns01.ub3rgeek.net. 21600 IN A 69.55.65.182 ns02.ub3rgeek.net. 21600 IN A 198.199.103.32 ;; Query time: 75 msec ;; SERVER: 2606:c380:c001:3::3#53(2606:c380:c001:3::3) ;; WHEN: Fri Mar 19 20:12:03 EDT 2021 ;; MSG SIZE rcvd: 258
From the ->>HEADER<<- section you can see that this was answered with AUTHORITY which means we asked the authoritative server the question. That would be 0 if we asked a recursive resolver and it had to go fetch the answer on our behalf.
Next time, we'll put this all together and talk about a useful BIND feature (and the reason I run such a strange setup with BIND forwarding to Unbound to get DNS over TLS) called views, that lets us serve different zones based on where our client is coming from.
🚀 © MMXX-MMXXIII matt@going-flying.com