What is Split-Brain DNS?

When building a lab or any services, you’re going to need DNS in most cases, however, we don’t necessarily want to expose the DNS records to the world, this is where resources like Split-Brain DNS servers come into play.

Split-Brain DNS??

Split-Brain DNS is effectively like having two DNS servers running on the same origin, they each have a set of records, and will reply different values depending on how they’re being requested. It seems complex, but it’s very easy to use.

Let’s say I’m connecting from my bedroom PC to my home wifi, and I want to ping my Nextcloud instance, I run “ping cloud.thegeekbin.com” and it returns “10.24.40.2” – perfect, I can access that and easily use it. Now, if I switched over to LTE network and ran the same command, I get a resolution error: “ping: cannot resolve cloud.thegeekbin.com: Unknown host”

We’re getting this DNS resolution error because our Split-Brain DNS sees the requesting IP address is outside the LAN scope, and returns an altered set of results. Let’s say your Jira instance was internally 10.24.42.2, and externally you used your public IPv4 address – when you queried externally, you’d get your public (eg. 123.123.123.123), but when looking from internal, you get the direct IP of the instance, which is 10.24.42.2, allowing you to skip going outside your network, and remaining entirely local.

Why do I want Split-Brain DNS?

In most cases, it’s for security and privacy, you obviously don’t want to expose to the world the topology of your entire network, right? By using split-brain you can expose just the public network to the public, and the whole private to the internal LAN, allowing you keep your topology private.

How do I set it up?

Setting up is easy, for this example I’m going to assume you’re running on Ubuntu or Debian for your DNS server, however, this should also work for CentOS/RHEL.

First, you’re going to want to install bind9 if you haven’t already, you can do this by running:

sudo apt-get install bind9 --yes

Now that we’ve got our basic DNS server installed, we’ll want to head over to /etc/bind/named.conf.options and make sure our configuration for listening on port 53 and the IP address is set, below is an example of the configuration file (tweak as necessary):

options {
    listen-on port 53 { 10.220.220.220; 127.0.0.1; };
    directory "/var/cache/bind/";
    allow-query { any; }
    recursion no;
    pid-file "/run/named/named.pid";
    notify yes;
}

Now we’ve got our basic setup ready, but we’re not done yet! We can now create access controls and views. Views are how the split-brain defines the resolution rules, for example, let’s create an ACL for our public network on 10.0.0.0/24, and a simple zone for “test.thegeekbin.com”:

acl "geekbinlan" { 10.0.0.0/24; };
view "geekbinlanview" {
    match-clients { "geenbinlan"; };
    zone "test.thegeekbin.com" {
        type master;
        file "test.thegeekbin.com.lan.zone";
    };
};

Now, we can define our rules inside the zone file for our lan, next we’ll want an outside view, which the public network will see, this will be considered the untrusted segment of the network, for this, we’ll create another view that matches on any clients like so:

view "geekbinwan" {
    match-clients { any; };
    recursion no;
    zone "test.thegeekbin.com" {
        type master;
        file "test.thegeekbin.com.wan.zone";
    };
};

Now, when we save and restart bind, throw some entries in each configuration zone file, and query from internal and external, you’ll see the bind server is responding with different entries based on the requesting IP address.

That’s all for this tutorial, leave me a comment below if you have any questions, I’d love to help out!