Revisiting Samba RODC + Bind
Ok, so here’s another step in the evolution of my Samba4-RODC-based
DNS setup. First steps were setting up a Samba4 Read-Only DC in
my remote locations, so that DNS would be replicated to that location so
that DNS doesn’t fail in case the VPN connection dies. Then we
discovered that the SAMBA_INTERNAL
DNS backend does not
support caching, which unsurprisingly lead to performance problems, so
we switched to Samba AD DC with
Bind as DNS backend. This setup is quite a bit more complex though,
and it seems a bit unstable in the sense that Samba lost its ability to
update records in Bind for some reason and we have to “fix” that
manually by re-joining the RODC to the domain. Rumor has it that the
SAMBA_INTERNAL
backend is a lot more stable. So, here’s
step three in our evolution: Let’s allow Samba to use
SAMBA_INTERNAL
, but only run on 127.0.0.1
,
while communication with the outside world is handled by a
bind
instance that handles caching and forwards queries for
the company domain records to Samba.
Configuration
The config is actually pretty easy (way simpler than getting the
“official” way to work, I might add). Just define a forward-only zone in
/etc/bind/named.conf.local
that forwards to
127.0.0.1
:
zone "local.lan" {
type forward;
forward only;
forwarders { 127.0.0.1; };
};
Then tell bind to only listen on the external interface (so bind and samba don’t fight over who gets to listen where):
options {
listen-on { 192.168.0.5; };
listen-on-v6 { none; };
};
(I disabled IPv6 because I don’t use it. Feel free to put your IPv6 address here if you have one.)
Next, set up Samba to listen only on the lo
interface:
[global]
bind interfaces only = yes
interfaces = lo
Re-join samba using the SAMBA_INTERNAL
dns backend,
start it up, and that’s it!
Verifying that it works
Let’s verify that we’re actually achieving what we want to. We’ll
start by checking that Samba, when used as a recursor to resolve
external Domains, really doesn’t cache the replies. We’ll do that by
running tcpdump -n -i <iface> udp and port 53
both
for lo
and eth0
, and seeing what requests are
being made.
“Public” domains (aka, non-AD)
When I repeatedly ask Samba for google.com
, here’s what
tcpdump
says:
08:28:54.975100 IP 192.168.0.5.48469 > 8.8.8.8.53: 6435+ [1au] A? google.com. (39)
08:28:54.984524 IP 8.8.8.8.53 > 192.168.0.5.48469: 6435 1/0/1 A 216.58.210.14 (55)
08:28:55.231383 IP 192.168.0.5.33705 > 8.8.8.8.53: 58051+ [1au] A? google.com. (39)
08:28:55.233150 IP 8.8.8.8.53 > 192.168.0.5.33705: 58051 1/0/1 A 216.58.210.14 (55)
08:28:55.453384 IP 192.168.0.5.58312 > 8.8.8.8.53: 35012+ [1au] A? google.com. (39)
08:28:55.455038 IP 8.8.8.8.53 > 192.168.0.5.58312: 35012 1/0/1 A 216.58.210.14 (55)
08:28:55.870107 IP 192.168.0.5.37276 > 8.8.8.8.53: 48778+ [1au] A? google.com. (39)
08:28:55.871942 IP 8.8.8.8.53 > 192.168.0.5.37276: 48778 1/0/1 A 216.58.210.14 (55)
08:28:56.278881 IP 192.168.0.5.51132 > 8.8.8.8.53: 25423+ [1au] A? google.com. (39)
08:28:56.280554 IP 8.8.8.8.53 > 192.168.0.5.51132: 25423 1/0/1 A 216.58.210.14 (55)
For every time that I try, I see exactly one request going to
8.8.8.8
(which I configured as a forwarder in
smb.conf
for this experiment).
Sending numerous requests to bind
instead, I only get
this once:
08:29:27.625128 IP 192.168.0.5.36198 > 192.54.112.30.53: 58507 [1au] A? google.com. (51)
08:29:27.627388 IP 192.54.112.30.53 > 192.168.0.5.36198: 58507-| 0/7/3 (509)
08:29:27.632826 IP 192.168.0.5.43989 > 216.239.34.10.53: 37612 [1au] A? google.com. (51)
08:29:27.654861 IP 216.239.34.10.53 > 192.168.0.5.43989: 37612*- 1/0/1 A 216.58.208.46 (55)
08:29:27.655430 IP 192.168.0.5.53348 > 192.52.178.30.53: 28382 [1au] DS? google.com. (51)
08:29:27.685309 IP 192.52.178.30.53 > 192.168.0.5.53348: 28382*-| 0/4/1 (466)
Bind has to ask multiple servers because I haven’t configured a forwarder, which is why we see multiple requests to different servers here. These serve to answer my first query. When I repeat the query however, I don’t see bind making any more requests: It just uses the response from its cache. So this works. :)
Company domains (resolved through AD)
Now let’s see what happens when we ask bind to resolve a
company-internal DNS record for puppet
. I have not asked
bind
to resolve this record before, so it isn’t cached and
Bind needs to ask Samba. Here’s what happens:
08:22:32.180238 IP 192.168.0.5.39036 > 192.168.0.5.53: 58534+ [1au] A? puppet.local.lan. (64)
08:22:32.181239 IP 127.0.0.1.46718 > 127.0.0.1.53: 57623+ A? puppet.local.lan. (41)
08:22:32.182392 IP 127.0.0.1.53 > 127.0.0.1.46718: 57623*- 1/1/0 A 192.168.212.100 (115)
08:22:32.183056 IP 192.168.0.5.53 > 192.168.0.5.39036: 58534 1/13/1 A 192.168.212.100 (320)
We see four packets here:
- My request to bind
- bind’s request to samba
- samba’s answer for bind
- bind’s answer for me.
Now if I just repeat exactly the same query, Bind should have cached the answer and it should not ask Samba again:
08:23:28.037650 IP 192.168.0.5.49563 > 192.168.0.5.53: 40889+ [1au] A? puppet.local.lan. (64)
08:23:28.038185 IP 192.168.0.5.53 > 192.168.0.5.49563: 40889 1/13/1 A 192.168.212.100 (320)
We now only see two packets:
- My request to bind
- bind’s answer for me.
We do not see a request being made to samba first, so it works as intended.
I’m not sure if caching of internal names is actually desirable. Maybe it would be better to ask Samba every time for these, because Samba actually has a copy of the authoritative database locally, so performance-wise, querying Samba every time should be fine. By having bind cache these entries, updates will be delayed by the TTL. I don’t think it’ll cause problems, but it’s probably something to be aware of.