Open-source project
mokeyish/smartdns-rs avatar
mokeyish/smartdns-rs

smartdns-rs and the case for a local resolver that picks the fastest address

A cross platform local DNS server (Dnsmasq like) written in rust to obtain the fastest website IP for the best Internet experience, supports DoT, DoQ, DoH, DoH3.

1,038 stars77 forksRustGPL-3.0

At a glance

What is it?
SmartDNS-rs is a Rust rewrite of the C SmartDNS local DNS server, querying several upstreams at once and returning the address that responds fastest, with DoT, DoQ, DoH and DoH3 support and a configuration format kept compatible with the original. It runs on Windows, macOS, Linux and Termux, and the README asks you not to use it in production yet.
Who is it for?
Adopt smartdns-rs if you run a home or small office network where DNS selection, ad filtering and encrypted upstreams matter, and you want a single native binary on Linux, macOS or Windows instead of a container.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A local resolver that answers with the fastest address

SmartDNS-rs is a local DNS server, described as dnsmasq like, that accepts DNS queries from local clients, obtains results from multiple upstream DNS servers, and returns the fastest access result to the client. The stated goals are avoiding DNS pollution and improving network access speed, with high performance ad filtering alongside.

The idea behind returning the fastest address is the thing that separates this from a plain forwarding resolver. When a domain resolves to several addresses, a conventional resolver hands the client the full set and lets the operating system pick, often favouring the first one. A local resolver that measures can instead hand back the address that actually answered first, which on a network with international links or a mixture of IPv4 and IPv6 is often the difference between a fast page and a slow one.

The project is explicitly inspired by the C SmartDNS, and the reason for the rewrite is stated: the C version is very functional but only supports Linux, while macOS and Windows can only be supported through Docker or WSL. The author's goal is a version that compiles to Windows, macOS, Linux and the Android Termux environment, and that stays compatible with the existing configuration.

Two statements in the README should shape any evaluation. The first is that it is still under development, please do not use it in production environment, welcome to try and provide feedback. The second is that the function coverage is tracked in a TODO file, which is the honest way to find out whether the feature you care about is implemented.

The audience is a technically confident home user or homelab operator who already knows what a local resolver is for.

Every upstream is queried at the same time

The multiple upstream feature is described in a way that reveals the design: it supports configuring multiple upstream DNS servers and querying them at the same time, and the query will not be affected even if there is a DNS server exception.

That is a different behaviour from a resolver that walks its list in order. Sequential failover means the user waits for the first server to time out before the second is tried, and on a network where one upstream is blocked or slow, that delay is paid on every cold query. Querying in parallel and taking the best answer removes the timeout from the critical path, and the failure of one server stops mattering.

The cost is that every query goes to every upstream in its group, which is exactly what a user who cares about DNS privacy might not want. The protocol features are the counterweight, since DoT, DoQ, DoH and DoH3 all encrypt the path to the upstream, and the configuration example sets up two bootstrap resolvers that are used to resolve the other upstreams rather than to answer queries, marked with the -bootstrap-dns and -exclude-default-group flags.

That is a well thought out configuration, and it is worth understanding the group mechanism to read it. A server can be assigned to a group, the default group is excluded for a particular server, and domain patterns are then routed to a group with a nameserver rule, in the example forwarding every name ending in ofc to the office group that points at the local router.

The domain rule mechanism is what makes ad blocking and local overrides possible without touching the upstreams. The address directive sets a static IP for a domain, and the same directive with a # value blocks a domain outright, so a blocked name resolves to nothing rather than being forwarded upstream.

Configuration that stays compatible with the C original

The configuration format is the same one the C SmartDNS uses, which is the single most useful thing about this project for an existing user, because the advanced documentation is the C project's configuration document and the same file can be moved between the two implementations.

The example in the README is close to a minimal working configuration and shows the shape of the format:

conf
bind 127.0.0.1:53
server https://1.1.1.1/dns-query  -bootstrap-dns -exclude-default-group
server https://cloudflare-dns.com/dns-query
server 192.168.1.1 -exclude-default-group -group office
nameserver /ofc/office
address /test.example.com/1.2.3.5
address /ads.example.com/#

Three things are visible there. The server directive takes a URL, so an encrypted upstream is configured the same way as a plain one. The group and exclude-default-group flags decide which queries a server sees, so the local router can answer the office names and nothing else. And the address directive handles both overrides and blocking, with a literal IP for one domain and # for another.

Two directives exist only in the Rust version, and the README says so. The server-h3 directive configures DoH3, and the server-quic directive configures DoQ, and the C SmartDNS does not support either.

The features list adds forwarding with ipset and nftables support, including setting the domain result into an ipset or nftables set when the speed check fails, which is the mechanism for steering a slow or unusable address onto a different path at the firewall level rather than only in DNS.

The protocol set is a set of build features

The Cargo manifest is where the shape of the implementation is clearest, and the feature list is long enough to be worth reading line by line.

The default feature set is common plus self-update, and common pulls in resolve-cli, dns-over-tls, dns-over-https, dns-over-quic, dns-over-h3, mdns, dnssec, service, nft, nom-recipes-all, swagger-ui-cdn, http_client and serde. The four encrypted protocols are separate features, each one switching on a ring based crypto backend in the hickory libraries, with tls-ring for DNS over TLS, https-ring for DNS over HTTPS, quic-ring for DNS over QUIC and h3-ring for DNS over HTTP3. The same hickory stack also provides the mdns feature.

Two of the features are about policy rather than protocols. The nom-recipes family holds the rules for matching IPv4 and IPv6 addresses and MAC addresses, and the IPv6 recipe depends on the IPv4 one because of IPv4 mapped IPv6 addresses, with a nom-recipes-mac variant for matching hardware addresses. The nft feature pulls in the external tools it needs, which is how the nftables integration writes its rules.

There are also a few features that exist for the project's own development, a failed_tests feature, a disable_icmp_ping switch and a future-diagnostic feature that pulls in a console subscriber, and the lints section configures check-cfg for a nightly cfg.

The package itself is smartdns at version 0.13.1, on edition 2024 with a minimum Rust version of 1.96, licensed GPL-3.0-only, and published on crates.io with a Homebrew formula named smartdns.

Installing it, and running it as a service

On macOS the path is Homebrew, and the README notes that listening on port 53 requires root, so sudo is needed:

shell
brew update
brew install smartdns

The service command is worth remembering, because sudo smartdns service start for a brew installed smartdns is the same as sudo brew services start smartdns. On Windows and Linux you download a package from the releases page and decompress it, and the three steps are the same everywhere.

shell
./smartdns --help
./smartdns run -c ./smartdns.conf -v
./smartdns service --help

The run command starts it in the foreground, which the README describes as the easy way to check the running status, and -v prints debug logs. The service subcommand manages the background installation that starts at boot, and the note is that administrator or root permissions are required for that.

The service management is written to be the same command everywhere, which is a nice piece of design. On Windows it calls sc, on macOS launchctl or brew, and on Linux Systemd or OpenRc. One command, one mental model, three platforms, and the same built binary is what makes it possible.

Nightly builds are published separately through the nightly workflow, which is how you run a build that is newer than the last tag. The repository also carries a justfile for the developer workflow with build, test, clippy and package aliases, and it switches from cargo to cross when the USE_CROSS environment variable is true, which is how the Windows artefacts are produced from a Linux machine.

Diagnostics through CHAOS TXT and dig

One feature stands out because it is unusual and cheap: built-in diagnostics through the CHAOS TXT class, which lets you interrogate the running server with dig itself.

shell
dig @127.0.0.1 CH TXT whoami +short
dig @127.0.0.1 CH TXT smartdns +short
dig @127.0.0.1 CH TXT server-name +short
dig @127.0.0.1 CH TXT version +short
dig @127.0.0.1 CH TXT client_ip +short
dig @127.0.0.1 CH TXT client_mac +short

The whoami query returns the full identity of the server and the client as multiple TXT records, while the smartdns query returns the server identity alone. The rest are narrow, and the narrow ones are the interesting ones. client_ip reports the source address the server sees for the query, and client_mac reports the client hardware address from the ARP table, with the README noting that the MAC lookup needs the LAN and ARP to be available.

A suffix style is also supported, so a query ending in .json returns the same information in JSON form, which is what you want if a monitoring script is going to consume it.

The reason this matters is that a local DNS server sits in a position where a misconfiguration is invisible from the client. A client that resolves the wrong thing, or a device that never asks at all, is hard to diagnose without a way to ask the server what it thinks is happening. The CHAOS interface gives you that, using a tool that is already installed.

There is a Swagger UI served from the project as well, and the swagger-ui-cdn feature is part of the common set, so the HTTP API has a browsable interface.

GPL-3.0, a young crate, and an explicit warning

The licence is GPL-3.0-only, declared in the Cargo manifest with the text in the LICENSE file, and the project also ships a CODE_OF_CONDUCT and a CONTRIBUTING file.

The release history shows a young but active project. v0.13.1 was published on 2026-06-27, v0.13.0 on 2025-12-05 and v0.12.2 on 2025-06-22, so the minor line moves roughly every six months with patches in between. The repository is not archived and the last push was on 2026-10-11, which is recent, and the nightly workflow means there is a build newer than any tag.

The version number tells you something about the project's own view of itself. A 0.13 that has existed for a while, with a version 1.0 not yet reached, is a project that is comfortable labelling itself as pre-1.0, and the README's warning against production use is consistent with that.

The judgement for an adopter is that this is a capable, cross platform resolver with a design borrowed from a proven C implementation, an unusually good diagnostic interface, and an honest statement of its own limits. The risk is not that the ideas are wrong, it is that the coverage of the original is incomplete, and the TODO file is where you have to look before you rely on a specific feature. The other risk is the one the author names, that a pre-1.0 resolver sits in the path of every device on the network, so a bug in it is a bug in the whole network.

Editorial conclusion

Adopt smartdns-rs if you run a home or small office network where DNS selection, ad filtering and encrypted upstreams matter, and you want a single native binary on Linux, macOS or Windows instead of a container. Do not adopt it for production, because the project says plainly that it is still under development and asks you not to use it in production, and do not adopt it if you need the full feature set of the C original, since the README points at a TODO file for function coverage. Verify three things first: that the features you need are covered, by reading TODO.md rather than the feature list, that your configuration will be interpreted the same way as the C version it was written for, and that the protocol you want is in the build, since DoT, DoH, DoQ and DoH3 are Cargo features. The last push was on 2026-10-11 and the newest release is v0.13.1 from 2026-06-27.

Frequently asked questions

What is smartdns-rs?

A cross platform local DNS server written in Rust, inspired by the C SmartDNS, that accepts queries from local clients, queries multiple upstream DNS servers and returns the fastest access result. It is licensed GPL-3.0-only and is packaged as the smartdns crate.

Which DNS protocols does smartdns-rs support?

UDP, TCP, DoT, DoQ, DoH and DoH3, as well as queries on non-53 ports and DNS over a socks5 or http proxy. The four encrypted protocols are separate Cargo features, and the configuration adds server-h3 and server-quic directives that the C SmartDNS does not have.

How do I install smartdns-rs?

On macOS with brew install smartdns, and on Windows and Linux by downloading a package from the releases page and decompressing it. Listening on port 53 needs root, the foreground run is ./smartdns run -c ./smartdns.conf -v, and the background service is managed with the service subcommand, which uses sc on Windows, launchctl or brew on macOS and Systemd or OpenRc on Linux.

Can I keep my existing SmartDNS configuration file?

Yes, that is a design goal. The Rust version is compatible with the C SmartDNS configuration, the advanced documentation is the C project's configuration document, and the same bind, server, group, nameserver and address rules apply. The README points at a TODO file for the coverage of individual features.

How do I diagnose a running smartdns-rs server?

Through built-in CHAOS TXT queries answered by dig itself, for example dig @127.0.0.1 CH TXT whoami +short for the server and client identity, and separate queries for server-name, version, client_ip and client_mac, with a .json suffix available for machine readable output.

Is smartdns-rs ready for production use?

The README says it is still under development and asks that it not be used in a production environment. The newest release is v0.13.1 from 2026-06-27, the crate is on edition 2024 with Rust 1.96 as the minimum, and the last push was on 2026-10-11 with nightly builds published separately.

Official sources

  1. Issues
  2. License: GPL-3.0
  3. mokeyish/smartdns-rs on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mokeyish-smartdns-rs.svg)](https://hysenlabs.com/projects/mokeyish-smartdns-rs)

Was this useful?