A logo showing a blue circle
Vlad-Stefan Harbuz

User-Friendly Hostnames with Yggdrasil

Yggdrasil allows you to easily set up a private virtual network based on IPv6. Your machines will then receive an IPv6 address such as 201:2af6:fcc4:30e7:b22d:15d6:a55d:10bb. However, that’s not very fun to have to type, and it would be nicer to be able to refer to your machines by their hostnames, e.g. by doing ping apples and ping pears.

I tried to do this in an intelligent way and failed, which led me to resort to setting up a local dnsmasq server to solve the problem. Still, I thought I’d write about my reasoning, since it could lead to a better solution in the future.

Hosts file

The most obvious solution is to stick some entries like this in /etc/hosts:

201:2af6:fcc4:30e7:b22d:15d6:a55d:10bb apples
202:a024:caff:1010:b501:14e2:ee1e:4400 pears

However, I don’t like this solution, because this file needs to be in a system-wide location, which means it’s difficult to version, which in turn means you have to update it separately on each machine. Let’s look for something else.

mDNS

Usually, you might accomplish this using something based on multicast DNS (mDNS), such as Avahi. These solutions send out a multicast packet to all machines on some local network, asking for information about themselves. This means that all machines on the local network are automatically discovered with zero configuration and can be referred to by their hostnames out of the box:

vladh usu ~:main $ avahi-browse -a
+ wlp0s20f3 IPv6 usu [d8:3b:bf:b3:c7:2a]        Workstation          local
+ wlp0s20f3 IPv6 Music Player @ usu[443]        Music Player Daemon  local
+ wlp0s20f3 IPv4 RouterA [00:11:32:ab:55:bf]    Workstation          local
+ wlp0s20f3 IPv4 RouterB [00:11:32:b1:87:4d]    Workstation          local
+ wlp0s20f3 IPv6 RouterB [00:11:32:b1:87:4d]    Workstation          local
+ wlp0s20f3 IPv4 EPSON WF-7710 Series           UNIX Printer         local
+ wlp0s20f3 IPv4 XXXXX___s iPhone               _rdlink._tcp         local

Unfortunately, Yggdrasil doesn’t support multicast networking, so this won’t work. Still, perhaps we can get some hints if we look at how mDNS is integrated into the Linux networking stack.

nsswitch

On glibc-based distros, hostnames will be resolved using a list of strategies listed in /etc/nsswitch.conf. We’re interested in the hosts entry, and here’s what that might look like:

hosts: mdns_minimal [NOTFOUND=return] files dns

This is saying that, first of all, the mdns_minimal plugin should be tried, which is the plugin that calls out to Avahi to make that multicast request. If that doesn’t work, we can try using the files plugin, which just looks the hostname up in /etc/hosts. If our hostname is not in there either, we fall back to the dns plugin, which looks up the nameserver we’re using in /etc/resolv.conf and makes a DNS request.

The ideal solution would probably involve adding some kind of yggdrasil plugin, which asks Yggdrasil for the list of peers we can connect to and attempts to resolve hostnames that way.

Unfortunately, this plugin doesn’t exist (perhaps you want to write it?). Additionally, nsswitch is only supported in glibc-based distros, so musl-based distros such as Alpine Linux would not support this approach at all, just like they don’t support any kind of mDNS.

dnsmasq

None of the things we’ve tried so far ended up working, so let’s just set up the most obvious solution. We could run our DNS requests through a local instance of lightweight DNS server dnsmasq. Then, we can tell dnsmasq to return a specific IP when queried for the address of a certain host.

I use NetworkManager, so I set up dnsmasq with it as described on ArchWiki. Then, I created a dnsmasq.conf file in /etc/NetworkManager/dnsmasq.d with the following contents:

addn-hosts=/home/vladh/.config/hosts

The ~/.config/hosts file contains what you would normally put in /etc/hosts:

201:2af6:fcc4:30e7:b22d:15d6:a55d:10bb apples
202:a024:caff:1010:b501:14e2:ee1e:4400 pears

However, this file is inside my home folder, so it’s very easy to version. Also, running dnsmasq has some other benefits, such as the performance boost gained from having a local caching DNS server. I will also use this file to define custom hosts for other purposes than Yggdrasil, for example to make up for the lack of mDNS support on Alpine Linux.

The downside is that hosts are not automatically detected, so you still have to update a file when you add a new machine.

Overall, I think this solution is good enough. Let me know if you know of a better approach!