Security Hardening
BoronDNS is designed to be secure by default. It is authoritative-only, refuses recursion unconditionally, and is written in safe Rust — unsafe code is forbidden by lint across the core and server crates, and the small amount of unsafe needed for the high-rate packet path is isolated in separate components and tracked in an explicit unsafe-boundary registry.
Threat model
BoronDNS receives zone data from a trusted primary nameserver and answers DNS queries from the internet. The main risks are:
- Zone data poisoning — an attacker injecting false zone data via a spoofed AXFR/IXFR
- Amplification attacks — BoronDNS being used to reflect/amplify DNS traffic
- Denial of service — exhausting file descriptors, memory, or CPU under flood conditions
- Information disclosure — exposing internal zone data or server version to hostile clients
TSIG for all zone transfers
Every [[zones]] block should reference a TSIG key. Without TSIG, any host that can reach your primary can clone your zones.
[[zones]]
name = "example.com."
primaries = [{ address = "10.0.0.1", port = 53 }]
tsig_name = "my-key" # never omit this in production
See TSIG Setup for key generation and primary configuration.
XoT — encrypted zone transfers
For the strongest transfer security, use Zone Transfer over TLS (XoT, RFC 9103). BoronDNS enforces TLS 1.3-only with SNI, ALPN dot, and no cleartext fallback:
[[zones]]
name = "example.com."
primaries = [{ address = "10.0.0.1", port = 853 }]
tsig_name = "my-key"
xot = {
trust_anchor = "/etc/borondns-secondary/ca.pem"
# Optional mTLS client certificate:
# client_cert = "/etc/borondns-secondary/client.crt"
# client_key = "/etc/borondns-secondary/client.key"
}Restrict NOTIFY sources
Accept NOTIFY messages only from your known primaries:
[acl]
notify_allow = ["10.0.0.1/32", "10.0.0.2/32"]Run as a non-root user
BoronDNS binds to port 53 using CAP_NET_BIND_SERVICE, then drops all capabilities. Never run as root.
The systemd unit installed with BoronDNS already sets:
User=borondns
Group=borondns
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
Set in config.toml:
[process]
disable_core_dumps = true
no_new_privileges = trueFail-closed zone publication
A transferred zone that cannot be compiled and served cleanly is rejected outright — never served half-applied. If a zone expires and the primary is unreachable, BoronDNS continues serving stale data until the SOA expire time, then stops answering queries for that zone rather than serving incorrect data.
Response Rate Limiting and DNS Cookies
Enable both to blunt UDP floods, reflection, and spoofing:
[rrl]
enabled = true
responses_per_second = 20
window = 15
[dns_cookies]
enabled = true
# For anycast/load-balanced fleets, configure a shared server secret for RFC 9018 compatibility:
# server_secret = "/etc/borondns-secondary/cookie-secret.key"
DNS Cookies support staged secret rollover for load-balanced and anycast fleets.
Firewall rules
Only port 53 (UDP and TCP) should be public-facing. The management port (default 8080) must never be reachable from the internet.
# nftables example: block management port from public internet
nft add rule inet filter input tcp dport 8080 ip saddr != 10.0.0.0/8 drop
nft add rule inet filter input udp dport 53 accept
nft add rule inet filter input tcp dport 53 accept
Additionally, ensure firewalls on DNS listener addresses allow ICMPv4 Fragmentation Needed and ICMPv6 Packet Too Big messages so Path MTU Discovery works for large EDNS UDP responses.
Version information
BoronDNS answers CHAOS TXT version.bind queries with "BoronDNS" and no version string. This is by design — exact version strings are not exposed.
Verify:
dig +short CH TXT version.bind @your-server
# "BoronDNS"Key and secret file permissions
All key and secret files should be owned by the borondns user and not readable by others:
sudo chown borondns:borondns /etc/borondns-secondary/keys/
sudo chmod 700 /etc/borondns-secondary/keys/
sudo chmod 640 /etc/borondns-secondary/keys/*.keyReporting vulnerabilities
If you discover a security issue, please report it privately:
- Email: security@integrity.hu
- Response SLA: acknowledgement within 24 hours, triage within 72 hours
We follow coordinated disclosure: we will work with you to develop a fix and notify you before public release.
Hardening checklist
-
TSIG key set on every
[[zones]]block -
notify_allowrestricted to known primary IPs in[acl] - XoT (DNS over TLS) configured for transfer transport
-
Running as non-root user with
CAP_NET_BIND_SERVICEonly - Firewall blocks management port 8080 from public internet
-
Key files owned by
borondnswith mode640 -
disable_core_dumps = trueandno_new_privileges = truein[process] -
ProtectSystem=strictandNoNewPrivileges=yesin systemd unit -
RRL enabled with
[rrl] enabled = true -
DNS Cookies enabled with
[dns_cookies] enabled = true - NTP configured and clock drift < 300 seconds (required for TSIG)
- Management HTTP listener bound to localhost or private network only