Tweaking Synology’s DNS Server For Great Justice

Years ago I purchased a Synology NAS (a DS1812+, if you must know). I also purchased some hard drives for it, and a 2GB stick of RAM (bringing its total up to 3GB). Under the hood it’s a dual-core Cedarview Atom x86 CPU, and it runs a Linux distro wherein the owner of the device also has root access (i.e., you own what you own, like in the good old days). It’s also got dual GB NICs, some USB ports, etc.

In addition to storing substantial slabs of data, you can install services on these devices, so in effect they’re more like mini servers than the NAS name might imply. It’s busybox-based though, so a lot of the normal Linux commands act weird or don’t have useful aliases (more, not less, only a subset of vi commands work, etc).

One of the services I opted to install was a DNS server, in the hopes that it would allow me to move some per-machine hosts file management stuff to it, and that our previously-rootless devices (read: iPads, iPhones, etc) would also be able to finally take advantage of a local caching name server with internal friendly names for devices that don’t participate in Bonjour. The package is called DNSServer, and it’s installed under the covers in /volume1/@appstore/DNSServer/, but it’s actually just named / BIND, wrapped up and redirected to run with config files in goofy places (goofy in that it’s standalone, so they’re local to the installation directory instead of using the more conventional /etc/ configuration path).

To get custom DNS overrides up and running, you can read the entire BIND manual, read lots of websites, and then still be frustrated that Linux server configuration is still basically stuck in 1968. To save you some time, I’ll provide you with a brainless recipe. This is no substitute for actually understanding the documentation, but on the other hand, this should enable you to actually use a machine you own to accomplish a task you’d like in a biologically sustainable period of time.

Starting off our exercise, let’s make a new zone file. With the default configuration, you’ll have a default master zone located in /volume1/@appstore/DNSServer/named/etc/zone/master. It will probably be named after your device’s hostname (in my case, I chose “homecloud”, so the default zone is called homecloud), and it’s pretty boring. I created a new zone file, called null.zone.file, and gave it the following contents:

$TTL    86400   ; one day
 
@       IN      SOA     ns0.example.net.      hostmaster.example.net. (
                        2016030100       ; serial number
                        28800   ; refresh  8 hours
                        7200    ; retry    2 hours
                        864000  ; expire  10 days
                        86400 ) ; min ttl  1 day
                NS      ns.homecloud.
        A   127.0.0.1
@       IN  A   127.0.0.1
*       IN      A       127.0.0.1

By itself, this doesn’t do much, but if you want to talk to others like you know what’s going on, it’s important to know that “SOA” means “Start Of Authority”, and that this provides just the “A” record (the IPv4 address — IPv6 addresses are AAAA records, MX records are for mail, and there’s a bunch of other random crap that is DNS records - we ignore those). There’s not much to know about the other stuff. It will point whatever domain in this zone to 127.0.0.1 (localhost, probably nowhere if you’re not running a web server locally).

In fact, when I said this doesn’t do much, I lied. It doesn’t do anything. It needs to be referenced for it to be used, and to do that, let’s move to the second step of our adventure, editing the config to have some domains that make use of our new zone.

Let’s make another zone file in /volume1/@appstore/DNSServer/named/etc/zone/data. Like the master zone directory, this will have a file named after your device, and it will contain a single zone that points to the zone file above (/etc/zone/master/homecloud in my case — it’s a relative path though). Next to this file, let’s add one called “drops”. Its contents will look something like this:

zone “hackers.com” { type master; notify no; file "/etc/zone/master/null.zone.file"; };
zone “virus.com” { type master; notify no; file "/etc/zone/master/null.zone.file"; };
zone “malware.com” { type master; notify no; file “/etc/zone/master/null.zone.file”; };

with an entry for each domain you’d like to kill (null.zone.file doesn’t point to any useful domain — you can make additional zone files that point to internal zones too, but I don’t want to reveal network internals here).

And, because this is simulating 1968, after adding these files, they still do nothing at all. This is nothing at all like hosts files, which do Exactly What You’d Expect with minimal muss and fuss. Those probably came about in the mid 1980s, judging by their relative user-friendliness.

To tie it all together, we now have to instruct named to load our zone config, which will in turn load our new zone files. To do that, we edit /volume1/@appstore/DNSServer/named/etc/zone/zone.load.conf

Initially, it looks something like this:

view "homecloud" {
    match-clients {any;};
    include "/etc/zone/data/homecloud";
};

Which tells it to include all those files we saw earlier. If we add another include line, we can get it to load our newly created stuff too. Make it look like this:

view "homecloud" {
    match-clients {any;};
    include "/etc/zone/data/homecloud";
    include "/etc/zone/data/drops";
};

And now we’re good to go. Oh wait, still 1968, so there’s one more thing: in the DSM web UI, Stop and Restart the DNSServer service. It will reload the configuration when it restarts, and you should be able to see your changes by using nslookup:

$ nslookup malware.com
Server:     10.xxx.yyy.zzz
Address:    10.xxx.yyy.zzz#53
 
Name:   malware.com
Address: 127.0.0.1

There you have it. I hope I saved you a few days of manual reading.