User Tools

Site Tools


samba:resilient-dns

Resilient DNS Forwarding Setup for Samba AD

This setting is recommended if you use more than one DNS forwarder for resilience. This setup uses dnsdist as an intelligent DNS proxy in front of your normal forwarders, with Samba DCs configured to forward external DNS queries through `dnsdist`.

Limitations: Samba Failover Delay

While `dnsdist` provides fast and intelligent failover between DNS forwarders (e.g., Pi-hole instances), Samba's internal DNS server introduces a noticeable delay before switching to an alternate forwarder when the primary becomes unavailable.

This happens because Samba tries to contact the first configured forwarder and waits for the request to timeout, which can take several seconds per query. Only then does it attempt the next one. This sequential behavior causes temporary failures or latency spikes when a forwarder goes down.

To mitigate this, `dnsdist` is placed in front of the forwarders and Samba forwards all external queries to `dnsdist` alone, allowing fast switching and load balancing to be handled outside of Samba.

Overview

  • Samba AD DCs provides internal DNS for Active Directory.
  • dnsdist listens on `127.0.0.1:5353` and forwards queries to multiple (in my case) Pi-hole instances.
  • If one Pi-hole becomes unavailable, `dnsdist` quickly switches to the other.
  • All DNS requests go through `dnsdist`, enabling load balancing and failover.

Architecture

  • `samba-ad-dc` (internal DNS server)
    • ↳ forwards to `127.0.0.1:5353` (dnslist)
  • `dnsdist`
    • ↳ forwards to:
      • `192.168.0.25` (Pi-hole 1)
      • `192.168.0.26` (Pi-hole 2)

Installing dnsdist on Debian

apt update
apt install dnsdist

This installs `dnsdist`, its dependencies, and sets up the systemd service.

Basic working configuration

nano /etc/dnsdist/dnsdist.conf
-- Listen only on localhost, port 5353
setLocal('127.0.0.1:5353')
addLocal('[::1]:5353')
 
-- Accept queries only from localhost
setACL({'127.0.0.1/32', '::1/128'})
 
-- Load balancing policy: least outstanding queries
setServerPolicy(leastOutstanding)
 
-- Upstream server 1
newServer({
  address = "192.168.0.25:53",
  retries = 1,          -- Allow one retry for transient issues
  timeout = 0.5,        -- 500ms timeout
  checkInterval = 10,   -- Check every 10s for faster failure / availability detection
  checkType = "A",
  checkName = "debian.org"
})
 
-- Upstream server 2
newServer({
  address = "192.168.0.26:53",
  retries = 1,          -- Allow one retry
  timeout = 0.5,        -- 500ms timeout
  checkInterval = 10,   -- Check every 10s
  checkType = "A",
  checkName = "debian.org"
})
 
-- Last resort (gateway)
newServer({
  address = "192.168.0.253:53",
  backup = true,
  retries = 0,          -- No retries for fast failure
  timeout = 0.5,        -- 500ms timeout
  checkInterval = 15,   -- Check every 15s
  checkType = "A",
  checkName = "debian.org"
})

Enable and start the service

systemctl enable dnsdist
systemctl start dnsdist

Check that it is running:

systemctl status dnsdist

Manual DNS Query Test (dig)

To verify that `dnsdist` is listening correctly on port 5353 and responding as expected, a manual query was executed using `dig`:

dig @127.0.0.1 -p 5353 example.com
 
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra
;; QUESTION SECTION:
;example.com.	IN	A
 
;; ANSWER SECTION:
example.com.	299	IN	A	23.192.228.84
example.com.	299	IN	A	23.215.0.136
example.com.	299	IN	A	23.215.0.138
example.com.	299	IN	A	96.7.128.175
example.com.	299	IN	A	96.7.128.198
example.com.	299	IN	A	23.192.228.80
 
;; Query time: 8 msec
;; SERVER: 127.0.0.1#5353(127.0.0.1)
;; WHEN: Sat May 17 21:14:07 UTC 2025

This confirms that:

  • `dnsdist` is correctly listening on `127.0.0.1:5353`.
  • The forwarding logic to the upstream Pi-hole servers is functional.
  • Multiple A records are received, indicating full response handling.
  • Average response time was only 8 ms, showing low-latency resolution.

Samba Configuration (/etc/samba/smb.conf)

[global]
    dns forwarder = 127.0.0.1:5353
systemctl restart samba-ad-dc

Check that now Samba is resolving properly - note now we use port 53 instead of 5353 to make sure we query samba:

dig @127.0.0.1 -p 53 example.com
 
; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> @127.0.0.1 -p 53 example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37277
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1
 
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; EDE: 3 (Stale Answer)
;; QUESTION SECTION:
;example.com.			IN	A
 
;; ANSWER SECTION:
example.com.		0	IN	A	96.7.128.175
example.com.		0	IN	A	23.215.0.138
example.com.		0	IN	A	23.215.0.136
example.com.		0	IN	A	23.192.228.84
example.com.		0	IN	A	23.192.228.80
example.com.		0	IN	A	96.7.128.198
 
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Sat May 17 21:30:39 UTC 2025
;; MSG SIZE  rcvd: 142

dnsdist.conf cofig explained

-- Only listen on localhost, port 5353
setLocal('127.0.0.1:5353')
addLocal('[::1]:5353')

Configures `dnsdist` to listen only on `127.0.0.1` (loopback), port 5353. This prevents exposure to the network and avoids conflict with Samba DNS on port 53.

-- Allow only queries from localhost
setACL({'127.0.0.1/32', '::1/128'})

Restricts access to `dnsdist` so that only processes on the local machine (like Samba) can query it.

-- Use leastOutstanding for smart load balancing
setServerPolicy(leastOutstanding)

Server Policy: leastOutstanding

The `leastOutstanding` policy in `dnsdist` is a dynamic and intelligent load-balancing strategy. It selects the upstream server (forwarder) that currently has the fewest active, unanswered queries.

This approach distributes load more evenly under pressure by avoiding overloaded servers and preferring those that are currently faster or less busy.

  • For every incoming DNS query, `dnsdist` checks how many queries are currently “in flight” (sent but not yet answered) on each configured server.
  • It chooses the server with the lowest number of outstanding queries at that moment.
  • If two or more servers have the same count, it picks one at random.

Benefits

  • Reacts in real-time to server load and network delays.
  • More efficient than round-robin when under load.
  • Helps prevent slow responses caused by overloaded forwarders.

Use Case

In this setup, where Samba forwards DNS queries to `dnsdist`, and `dnsdist` balances between two Pi-hole servers, `leastOutstanding` ensures that queries are directed to the least busy Pi-hole, improving performance and failover behavior. One last resort server (router) to be used if both upstreams are U/S

-- Upstream server 1
newServer({
  address = "192.168.0.25:53",
  retries = 1,          -- Allow one retry for transient issues
  timeout = 0.5,        -- 500ms timeout
  checkInterval = 10,   -- Check every 10s for faster failure / availability detection
  checkType = "A",
  checkName = "debian.org"
})

Upstream DNS server.

  • `retries=1`: Only try once before failing over to the next server.
  • `checkInterval=10`: Health check every 10 seconds.
  • `checkType=“A”` + `checkName=“debian.org”`: Performs an A record query to verify the server is alive.
-- Last resort
newServer({
  address = "192.168.3.253:53",
  backup = true,
  retries = 0,          -- No retries for fast failure
  timeout = 0.5,        -- 500ms timeout
  checkInterval = 15,   -- Check every 15s
  checkType = "A",
  checkName = "debian.org"
})

Last resort Upstream DNS server.

  • `retries=0`: No retries for fast failure.
  • `backup = true`: Use only if other servers are both U/S
  • `checkInterval=15`: Health check every 15 seconds.
  • `checkType=“A”` + `checkName=“debian.org”`: Performs an A record query to verify the server is alive.

DNS Load & Failover Test with dnsperf

To verify the resilience and failover handling of `dnsdist`, a 30-second DNS stress test was performed using `dnsperf`. The forwarders configured in `dnsdist` were two Pi-hole servers. During the test, one of the Pi-hole forwarders was deliberately shut down after 10 seconds to simulate a failure.

Test Details

dnsperf -s localhost -d queries.txt -l 30
  • Target: Samba AD-DC (localhost)
  • Duration: 30 seconds
  • Query file: 1000 unique fake domains (e.g. test1.example.com to test1000.example.com) to avoid cache hits

Output

Queries sent:         105909
Queries completed:    105859 (99.95%)
Queries lost:         50 (0.05%)
 
Response codes:       NOERROR 105859 (100.00%)
Average packet size:  request 36, response 77
Run time (s):         30.43
Queries per second:   3478.13
 
Average Latency (s):  0.026
Latency StdDev (s):   0.0526

Despite shutting down one Pi-hole during the test:

  • Only 50 queries were lost (0.05%), which were quickly retried and resolved.
  • All valid responses had NOERROR status.
  • `dnsdist` recovered from the failed forwarder automatically and quickly, showing excellent failover behavior.
  • The system maintained an average throughput of 3478 QPS with low latency, indicating that the setup is stable even under load and partial failure.

`dnsdist`, configured with `leastOutstanding` policy and `retries=1`, provides a robust DNS load balancing and failover mechanism suitable for critical infrastructure such as Samba AD environments.

External Resources


Caponato's Samba notebook. Start here or else Main menu

samba/resilient-dns.txt · Last modified: by caponato