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
tinydns
listen on 127.0.0.1 - create the
ip
files for dnscache - create the
servers
file 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:
tinydns
listens on 127.0.0.1tinydns
answers queries related to *.domain.landnscache
answer queries from any addressdnscache
forwards queries related to *.domain.lan to ip 127.0.0.1dnscache
forwards everything else to others DNSdnscache
answers 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.