Configure a local authoritative DNS in FreeBSD Jail
An authoritative DNS jailed
Since when I installed my FreeBSD box I’ve tried a lot of different services/servers, each one of them is jailed.
Starting with a simple vpn service based on OpenVPN, till a “local-authoritative” DNS server; which could be useful in a home environment, tipically statically served in terms of IP allocation.
Environment preparation
First of all a new jail must be settled up (see the Define Jail part of the OpenVPN post), then we can proceed to the jail initialization and configuration.
You can find a some hints on the OpenVPN guide to setup the jail, then we have to connect to it and bootstrap all the necessary systems. First of all we have to connect to the already defined jail using jexec <jail-name> tcsh
, then we have to bootstrap the package manger pkg bootstrap && pkg upgrade -y
and then we can start to install packages.
I’ve used bind9
as DNS server because is the most reliable and RFC compliant DNS server nowadays, and also is the most well-documented and *nix compliant server.
We have to install the bind9
package using: pkg install -y bind9
, then we have to enable it in /usr/local/etc/rc.conf
manually (or using echo 'named_enable="YES"' >> /usr/local/etc/rc.conf
), or delegating to the sysrc
system tool running sysrc named_enable="YES"
.
DNS Configuration
The DNS server configuration is not complicated, we have to edit the configuration file, and then we have to define our zone files. The configuration must be made, as always, inside the appropriate jail.
We have to edit the named
configuration file which is located in /usr/local/etc/namedb/named.conf
like this:
acl goodclients { # A list of "good clients" in terms of which networks are allowed to query the DNS server
192.168.1.0/24; # My local network
192.168.177.0/24; # My jail network
192.168.188.0/24; # My vm network
localhost;
localnets;
};
options{
...
listen-on { 127.0.0.1; <your-jail-ip>; };
notify yes;
recursion yes;
allow-recursion { goodclients; };
forwarders { # We want to forward each unknown request to other dns services
8.8.8.8;
8.8.4.4;
};
...
}
Then we have to define our zones, first of all we have to add them to the configuration file:
...
options{
...
}
...
zone <your-zone-name> {
type master;
file "/usr/local/etc/namedb/master/<zone-file-name>";
allow-transfer { none; };
}
zone "1.168.192.in-addr.arpa" {
type master;
file "/usr/local/etc/namedb/master/db.rev.192";
allow-transfer { none; };
};
The above snippet shows how to configure a standard DNS zone wit the respective reverse zone.
Now we have to define our dns zone file and the reverse one in the path defined in the configuration file. A zone file looks like this:
$TTL 604800
<zone-name>. SOA ns1.<zone-name>. root.<zone-name>. (
2018101901; Serial
3H; Refresh
15M; Retry
2W; Expiry/ 1D ); Minimum
; name servers - NS records
IN NS <zone-name>.
; name servers - A records
<zone-name>.unx. IN A <server-ip>
record1.<zone-name>. IN A <record1-ip>
record2.<zone-name>. IN A <record2-ip>
Instead a reverse zone file is like this:
; BIND reverse data file.
; The domain, etc. used should be a listed 'zone' in named.conf.
$TTL 86400
1.168.192.in-addr.arpa. IN SOA ns1.<zone-name>. root.<zone-name>. (
2018040501 ; Serial
10800 ; Refresh
3600 ; Retry
604800 ; Expire
86400 ) ; Minimum
; In this case, the number just before "PTR" is the last octet
; of the IP address for the device to map (e.g. 192.168.56.[3])
; Name Servers
IN NS ns1.<zone-name>.
; Reverse PTR Records
<last-octet-of-the-ip-address-of-the-server> IN PTR ns1.<zone-name>.
<last-octet-of-the-ip-address-of-the-record1> IN PTR record1.<zone-name>.
<last-octet-of-the-ip-address-of-the-record2> IN PTR record2.<zone-name>.
These files are the basic configuration for a DNS server exposed on a 192.168.1.0/24 network, but, as is visible from the first part of the configuration, there are multiple networks and services like the http server, and also intra-jail services (and of course I want to experiment!!!) which could require different views of the same zone; so I’ve modified the configuration and settled up two different views: one for the normal local network, and one for the jail networks.
The configuration file must be modified like this:
...
acl jails {
192.168.177.0/24 # my jail network
}
options {
...
}
view "jails" {
match-clients { jails; };
# Insert each zone from the original config files which are not interested
zone "masinihouse.unx" {
type master;
file "/usr/local/etc/namedb/master/<your-jail-related-db>";
allow_transfer {none;};
}
zone "1.168.192.in-addr.arpa" {
type master;
file "/usr/local/etc/namedb/master/db.rev.192";
allow_transfer {none;};
}
zone "177.168.192.in-addr.arpa" {
type master;
file "/usr/local/etc/namedb/master/db.rev.177";
allow_transfer {none;};
}
}
The only difference is that you have to specify the selected reverse zones and create an ACL for the view, also a separate database file with different records.
After the configuration run the rndc reload
command to reload the configuration of the DNS server, if is an “intermediate” configuration try to invalidate the DNS cache on your machine.
Note: each zone has allow_transfer
settled to none because this is the only dns server on my network, if there is another dns server (maybe a slave dns server) the allow_transfer must include the subnet or the specific ip address of the other dns server record (NS record type).
Jail and Server Configuration
We want to install a local-authoritative DNS server so we have to configure the firewall and then each jail to rely on the newest DNS server.
First of all we have to define the services on the firewall (bind is the name of my jail):
...
ext_if = "<you-public-iface>"
bind_jail_ip = "<your-jail-ip>"
bind_jail_udp = "{ rndc, domain }"
bind_jail_tcp = "{ domain }"
....
rdr pass on $ext_if inet proto udp to port $bind_jail_udp -> $bind_jail_ip
rdr pass on $ext_if inet proto tcp to port $bind_jail_tcp -> $bind_jail_ip
Then we have to instruct each jail, the hosting machine, and each machine on the same network to use the defined DNS server. To do it you have to configure in /etc/resolv.conf
the ip address of the jail/server depending on what device are you configuring (of course for Windows or Mac the configuration method is different). For example on a jail you have to define the resolv file like this:
search <your-base-domain>
nameserver <nameserver-jail-ip>
nameserver <another-fallback-dns>
Instead for the hosting server you have to configure the resolv file like this:
search <your-base-domain>
nameserver 127.0.0.1
nameserver <another-fallback-dns>
Then for another machine in your local area network:
search <your-base-domain>
nameserver <server-ip>
nameserver <another-fallback-dns>
Conclusions
Bind9 is a battle tested and rock solid DNS server, the configuration is pretty easy and fits perfectly for a home environment. BTW it does not have a feasible GUI which could be a plus, but with some scripts or at least a playbook the configuration could be fully automated.