Name that domain
10 July, 2014
Hello folks !
I recently reinstalled my home server, and during the process, I decided to
throw away the heavy BIND nameserver from my application stack. I decided to
go with the light couple tinydns + dnscache.
This wasn't really "easy" to do so, as there are really few resources on the web explaining the step to get this working (If you're aware of one, please send me a link, I'll be glad to share it). So here is a full tutorial !
TL;DR
- create tinydns zone file
- make
tinydnslisten on 127.0.0.1 - create the
ipfiles for dnscache - create the
serversfile for dnscache containing127.0.0.1 - Fire it up
- Enjoy.
The whole installation
First of all, I had to find out what were my needs. It seems stupid to say so, but I have the bad habit to dive into configuration, barely knowing what I'm trying to do. Here's what I wanted:
The DNS nameserver will be running on a machine with IP 10.0.0.1. My local network will be named domain.lan. I want all my machines to contact 10.0.0.1 to resolve URIs, and the server will provide authoritative answers for domain.lan, and forward everything else to some other servers.
How should we organise things then ?
Here's how I see it:
tinydnslistens on 127.0.0.1tinydnsanswers queries related to *.domain.landnscacheanswer queries from any addressdnscacheforwards queries related to *.domain.lan to ip 127.0.0.1dnscacheforwards everything else to others DNSdnscacheanswers on any address
Let's set this up then!
tinydns
tinydns is fairly simple to use, and even more simple to configure. But it's
nothing you've ever seen before. You can configure tinydns from a single file:
─── cat /etc/tinydns/root/data
Zdomain.lan:dns.domain.lan::contact.domain.lan
&domain.lan::dns.domain.lan
+domain.lan:10.0.0.1
+pc1.domain.lan:10.0.0.1
+pc2.domain.lan:10.0.0.2
That's a basic configuration file to use with tinydns. It will resolve
domain.lan and pc1.domain.lan to ip 10.0.0.1 and pc2.domain.lan to
10.0.0.2.
For more infos on the syntax, check the alpine wiki page.
Once your config file is created, you can generate the data that tinydns will
use. Remember to correctly set the ROOT variable to define the directory where
tinydns will store it's data:
# ROOT=/var/cache/tinydns/ tinydns-data
As we said earlier, we want tinydns to listen on the loopback interface. To do
so, we have to export the variable IP before running the binary.
# ROOT=/var/cache/tinydns/ IP=127.0.0.1 tinydns
And there you go ! Tinydns is listenning on address 127.0.0.1.
To check if it's correctly running, you can use nslookup.
# cp /etc/resolv.conf.old /etc/resolv.conf.orig
# cat <<EOF > /etc/resolv.conf
nameserver 127.0.0.1
EOF
# nslookup pc2.domain.lan
Server: (null)
Address 1: ::1 localhost
Address 2: 127.0.0.1 dns.domain.lan
Name: pc2.domain.lan
Address 1: 10.0.0.g.2
# mv /etc/resolv.conf.orig /etc/resolv.conf
It works ! Don't use tinydns as a resolv.conf entry though. Because it's authoritative and ONLY serves our domain.lan zone, it would not be efficient...
dnscache
No DNS server can answer all the queries, so in most case, if the DNS can't provide an answer, it will just forward the query to another depending on some internal rules.
That's how we're gonna set up dnscache. Intercept queries from the local
network, forward every query for domain.lan to tinydns, and everything to a
standard list of known root servers.
But first, we need to tell dnscache to answer every query from local domain.
Let's say my current configuration is the following:
Network : 10.0.0.0
Netmask : 255.255.0.0
Gateway : 10.0.0.254
DNS : 10.0.0.1
We need to listen on 10.0.0.0/16 for DNS queries. To set this up, take a look
at the /etc/dnscache/ip/ directory:
─── ls /etc/dnscache/ip
127
─── wc 127
0 0 0 /etc/dnscache/ip/127
A single file named 127, which is totally empty... What does that mean ?
Upon startup, dnscache will read this directory and check the filenames to
know which IP address it should accept queries from.
The filename also act as a netmask, so in this case, 127 really means
127.0.0.0/8.
Back to our configuration. We want dnscache to accept queries from our local
network: 10.0.0.0/16. Just create the corresponding file:
# :> /etc/dnscache/ip/10.0
And we're done !
Now, we need to tell dnscache who will answer the queries it receives. This is
done in the /etc/dnscache/servers/ directory. We can see that there is already
a file here:
─── ls /etc/dnscache/servers/
@
─── cat /etc/dnscache/servers/@
198.41.0.4
192.228.79.201
192.33.4.12
128.8.10.90
...
This is a list of the root servers extracted from this list.
In this directory, each file represent a domain, and the content of this file is
the list of the servers to contact in order to resolve those names.
"@" is a special name for the "fallback" entry.
In our case, we want tinydns to resolve names from "domain.lan", and forward
everything else to the root servers in the "@" file. To query tinydns, we
need to forward queries to 127.0.0.1. Here's how to do this:
# cat <<EOF > /etc/dnscache/servers/domain.lan
127.0.0.1
EOF
That's all. Pretty simple isn't it ?
It's now time to start dnscache. It needs (like tinydns) two environment
variables: ROOT for the configuration directory path, and IP for the address
of the interface to listen on (note that you can use 0.0.0.0 to listen on all
interfaces).
# ROOT=/etc/dnscache IP=10.0.0.1 dnscache
You can now check if everything is working fine with nslookup:
# cp /etc/resolv.conf.old /etc/resolv.conf.orig
# cat <<EOF > /etc/resolv.conf
nameserver 10.0.0.1
EOF
# nslookup pc2.domain.lan
Server: (null)
Address 1: ::1 localhost
Address 2: 127.0.0.1 dns.domain.lan
Name: pc2.domain.lan
Address 1: 10.0.0.g.2
# mv /etc/resolv.conf.orig /etc/resolv.conf
And there you are ! You can now specify the IP address of your server in the
resolv.conf on your local computers.