Getting an internally routed subdomain working
(Note: This post is originally from 2017, and is copied to this new site for historical reasons. Opinions, network infrastructure, and other things may have changed since this was first written.)
One of the things those fancy-pants corporate networks do that I’ve always wanted to set up is have an internally routed intranet kind of subdomain. They might call it corp.somewhere.com
or internal.somewhere.com
, and you’d be able to access certain services or perhaps specific boxes with an FQDN like printer-32.3rdfloor.internal.somewhere.com
.
Today, I set up internal.lavacano.net
for all addresses in my VPN’s subnet, 10.20.30.0/24
. Right at the moment, I’ve only got a handful of servers, so this doesn’t really do me a whole lot of practical good, but it’s a great party trick and a skill that will come in handy should I be put in charge of a network large enough to need this kind of thing.
Ingredients
- dnsmasq, one (or perhaps more) master server(s) and one for each additional Linux box that doesn’t have NetworkManager or something similar installed. Windows clients and Linux clients with NetworkManager or whatever installed can be made to automatically add the extra DNS information through a directive in OpenVPN’s server config:
push "dhcp-option DNS 10.20.30.1"
/etc/hosts.d/lavacano.net
, a file that dnsmasq will be configured to exclusively read DNS information from. dnsmasq doesn’t particularly give half a damn exactly what the file is named or what directory it’s in as long as it’s formatted like a hosts file, but it’s configured to read/etc/hosts
by default, and I’d rather keep it organized in case I can configure it to consider a whole directory later.- At least one fallback DNS server address. If your dnsmasq server doesn’t have an entry for it, it will query the fallback address for you (and cache the result if you’re into that kind of thing) and then forward the result to you. This is the part where you put in Google DNS, or OpenDNS, or both.
Server side
This is my server-side /etc/dnsmasq.conf
file:
# these two lines enable DNSSEC related things
# this file path is valid in Ubuntu 16.04, but you might want
# to double check it yourself
conf-file=/usr/share/dnsmasq-base/trust-anchors.conf
dnssec
# Google DNS
server=8.8.8.8
server=8.8.4.4
# OpenDNS
server=208.67.220.220
server=208.67.222.222
# define addresses to listen on
# 127.0.0.1 is not included by default, interestingly
listen-address=10.20.30.1
listen-address=127.0.0.1
# prevent reading /etc/resolv.conf, which is configured to point to this server
# infinite loops aren't a good thing
no-resolv
# hosts file related. disables reading from /etc/hosts and reads from
# /etc/hosts.d/lavacano.net instead
no-hosts
addn-hosts=/etc/hosts.d/lavacano.net
expand-hosts
domain=lavacano.net
domain=internal.lavacano.net,10.20.30.0/24
expand-hosts
and the domain
lines are perhaps the most interesting part. Consider these two lines of /etc/hosts.d/lavacano.net
:
149.56.132.23 andariel
10.20.30.1 andariel
All of my hosts are defined in this file similarly – using short names. dnsmasq was configured to expand those short names (the expand-hosts
directive), so the first line defines the IP 149.56.132.23
as andariel.lavacano.net
. The default domain is lavacano.net
(the first domain
line), and dnsmasq will assume that’s the domain for every short host it finds, if it has no reason to decide otherwise.
But there’s two domain
lines, and the second one defines a specific subnet that it applies to. Because the second line defining 10.20.30.1
falls within the subnet specified by the second domain
line, the short host there expands to andariel.internal.lavacano.net
.
In short, those two lines after expansion, according to the rules above, would look like this:
149.56.132.23 andariel.lavacano.net
10.20.30.1 andariel.internal.lavacano.net
Client side
This configuration file for the client defines Google DNS and OpenDNS as defaults, and defines 10.20.30.1
as the nameserver address for lavacano.net
and the 10.20.30.0/24
subnet (reverse DNS lookups). This has the added bonus of only making requests to the internal DNS for resources within the network.
{% capture dnsmasqcli %} server=8.8.8.8 server=8.8.4.4 server=208.67.220.220 server=208.67.222.222 server=/lavacano.net/10.20.30.1 server=/30.20.10.in-addr.arpa/10.20.30.1 listen-address=127.0.0.1 no-resolv no-hosts {% endcapture %} {% include filebox.html filename=”/etc/dnsmasq.conf” content=dnsmasqcli desc=”Client side configuration” %}
How, precisely, each client would need to be configured to use your dnsmasq instance as the primary DNS server depends on your distro, and in some cases some variables specific to that distro. Generally, getting nameserver 127.0.0.1
into /etc/resolv.conf
somehow will do it. This whole section can, again, be ignored if your Linux client has NetworkManager installed, or if it’s a Windows client. Macs, I don’t know anything about.
Does it work?
So how does one check to make sure you’ve applied these configurations correctly? Reconnect to the VPN and try to do some DNS lookups, of course.
(internal address check)
% nslookup andariel.internal.lavacano.net
Server: 10.20.30.1
Address: 10.20.30.1#53
Name: andariel.internal.lavacano.net
Address: 10.20.30.1
(outside addresses, did we isolate ourselves?)
% nslookup nicememe.website
Server: 10.20.30.1
Address: 10.20.30.1#53
Non-authoritative answer:
Name: nicememe.website
Address: 64.90.49.171
With 10.20.30.1
defined as the default DNS server, it’s exactly like Google or OpenDNS, except with extra entries for internal.lavacano.net
overlaid on top. I’d call that mission accomplished.
Now to get in the habit of typing internal DNS addresses everywhere so I can feel smug about it.