A high-performance, recursive DNS resolver server with DNSSEC support, focused on preserving privacy.
Use the go get
command to install sdns
:
go get github.com/semihalev/sdns
You can download the latest release from the Github Repo.
$ docker run -d --name sdns -p 53:53 -p 53:53/udp sdns
Install docker-compose
and run from the root directory:
$ sudo apt install docker-compose
$ docker-compose up -d
Install and run as a service:
$ brew install sdns
$ brew install semihalev/tap/sdns (updated every release)
$ brew services start sdns
$ snap install sdns
$ yay -S sdns-git
Note: Pre-built binaries, Docker packages, brew taps, and snaps are automatically created by Github workflows.
$ go build
$ make test
Flag | Desc |
---|---|
-c, --config PATH | Location of the config file. If it doesn't exist, a new one will be generated. |
-v, --version | Show the version of the sdns. |
-h, --help | Show this help and exit. |
To debug your environment, execute the following command:
$ export SDNS_DEBUGNS=true && export SDNS_PPROF=true && ./sdns
The SDNS_DEBUGNS
environment variable is beneficial for verifying the RTT (Round Trip Time) of authoritative servers. To use it, send an HINFO query for zones with chaos class.
Here's an example of the output you might receive:
$ dig chaos hinfo example.com
; <<>> DiG 9.17.1 <<>> chaos hinfo example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29636
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: f27dbb995df5ac79e4fa37c07d131b5bd03aa1c5f802047a7c02fb228a886cb281ecc319323dea81 (good)
;; QUESTION SECTION:
;example.com. CH HINFO
;; AUTHORITY SECTION:
example.com. 0 CH HINFO "Host" "IPv4:199.43.135.53:53 rtt:142ms health:[GOOD]"
example.com. 0 CH HINFO "Host" "IPv4:199.43.133.53:53 rtt:145ms health:[GOOD]"
example.com. 0 CH HINFO "Host" "IPv6:[2001:500:8f::53]:53 rtt:147ms health:[GOOD]"
example.com. 0 CH HINFO "Host" "IPv6:[2001:500:8d::53]:53 rtt:148ms health:[GOOD]"
Key | Description |
---|---|
version | Configuration version |
directory | sdns working directory (must grant write access to sdns user) |
bind | DNS server binding address Default: :53 |
bindtls | DNS-over-TLS server binding address Default: :853 |
binddoh | DNS-over-HTTPS server binding address Default: :8053 |
binddoq | DNS-over-QUIC server binding address Default: :853 |
tlscertificate | Path to the TLS certificate file |
tlsprivatekey | Path to the TLS private key file |
outboundips | Outbound IPv4 addresses (randomly chosen if multiple entries provided) |
outboundip6s | Outbound IPv6 addresses (randomly chosen if multiple entries provided) |
rootservers | DNS Root IPv4 servers |
root6servers | DNS Root IPv6 servers |
dnssec | DNSSEC validation on signed zones, off for disabled. |
rootkeys | Trusted DNSSEC anchors |
fallbackservers | Failover resolver IPv4 or IPv6 addresses with port (leave blank to disable) Example: "8.8.8.8:53" |
forwarderservers | Forwarder resolver IPv4 or IPv6 addresses with port (leave blank to disable) Example: "8.8.8.8:53" |
api | HTTP API server binding address (leave blank to disable) |
bearertoken | API bearer token for authorization. If the token set, Authorization header should be send on API requests |
blocklists | Remote blocklist address list (downloaded to the blocklist folder) |
blocklistdir | [DEPRECATED] Directory creation is automated in the working directory |
loglevel | Log verbosity level (crit, error, warn, info, debug) |
accesslog | Location of the access log file (leave blank to disable) Default: Common Log Format |
nullroute | IPv4 address for forwarding blocked queries |
nullroutev6 | IPv6 address for forwarding blocked queries |
accesslist | Client whitelist for query permissions |
querytimeout | Maximum wait duration for DNS query response Default: 10s |
timeout | Network timeout duration for each DNS lookup Default: 2s |
hostsfile | Enable serving zone data from a hosts file (leave blank to disable) |
expire | Default error cache TTL (in seconds) Default: 600 |
cachesize | Cache size (total records in cache) Default: 256000 |
prefetch | Cache prefetch before expiry (threshold: 10%-90%, 0 to disable) |
maxdepth | Maximum iteration depth per query Default: 30 |
ratelimit | Query-based rate limit per second (0 to disable) Default: 0 |
clientratelimit | Client IP address-based rate limit per minute (no limit if client supports EDNS cookie) Default: 0 |
blocklist | Manual blocklist entries |
whitelist | Manual whitelist entries |
cookiesecret | DNS cookie secret (RFC 7873) - auto-generated if not set |
nsid | DNS server identifier (RFC 5001) - useful for operating multiple sdns instances (leave blank to disable) |
chaos | Enable responses to version.server, version.bind, hostname.bind and id.server chaos txt queries |
qname_min_level | Qname minimize level (0 to disable - higher values increase complexity and impact response performance) |
emptyzones | Enable response to RFC 1918 zone queries. For details, see http://as112.net/ |
In sdns, you have the ability to add custom plugins. The sequence of the plugins and the middlewares has a mutual impact on their execution. Config keys must be strings, and values can be of any type. Plugins are loaded before the cache middleware in the specified order.
The plugin interface is straightforward. For additional information, please refer to the example plugin.
[plugins]
[plugins.example]
path = "/path/to/exampleplugin.so"
config = {key_1 = "value_1", intkey = 2, boolkey = true, keyN = "nnn"}
[plugins.another]
path = "/path/to/anotherplugin.so"
Benchmarks were performed on the following DNS resolvers: sdns-1.3.3, pdns-recursor-4.8.4, bind-9.19.12, unbound-1.17.1.
Resolver | RESPONSE | LOST | NOERROR | SERVFAIL | NXDOMAIN | Run Time | QPS |
---|---|---|---|---|---|---|---|
SDNS | 100% | 1 | 35,164 | 866 | 13,969 | 87s47ms | 571/s |
PowerDNS | 99.99% | 6 | 35,140 | 893 | 13,961 | 88s83ms | 563/s |
Bind | 99.74% | 132 | 35,024 | 885 | 13,959 | 127s64ms | 390/s |
Unbound | 99.49% | 253 | 35,152 | 624 | 13,971 | 174s64ms | 284/s |
We welcome pull requests. If you're considering significant changes, please start a discussion by opening an issue first.
Before submitting patches, please review our CONTRIBUTING guidelines.