Note: Let's DANE is still under development, use at your own risk.
Let's DANE enables the use of DANE (DNS Based Authentication of Named Entities) in browsers and other apps using a lightweight proxy. It currently supports DANE-EE and works with self-signed certificates.
torproject.org with DANE-EE validated certificate
Let's DANE acts as a trusted intermediary between the browser and DANE enabled sites. It will check if a domain supports it, and generate a certificate on the fly if the authentication was successful. The connection will remain encrypted between you and the end server. If a website doesn't support DANE, its original certificate will be served instead.
You are essentially trusting your own private certificate authority. You can install it in your browser's CA store to issue certificates for successful DANE authentications.
- Full DANE-EE support including self-signed certificates (RFC6698, RFC7671)
- Client-side DNSSEC validation using libunbound
- Prevents downgrade attacks to traditional CAs
- Lightweight DANE tunnels that work with most protocols and with ALPN support.
- Happy Eyeballs v2 (RFC8305)
You can build the latest version from source for now. binaries in releases are not up to date yet.
Go 1.21+ is required. (unbound is optional omit -tags unbound to use AD bit only)
apt install libunbound-dev
git clone https://github.com/buffrr/letsdane.git && cd letsdane/cmd/letsdane
go build -tags unboundLet's DANE will generate a CA and store it in ~/.letsdane when you start it for the first time.
To start the proxy server:
letsdane -r 1.1.1.1
-
Add Let's DANE proxy to your web browser
127.0.0.1:8080(Firefox example) -
Import the certificate file into your browser certificate store (Firefox example). You can use
letsdane -o myca.crtto export the public cert file to a convenient location.
If you don't specify a resolver, letsdane will use the system resolver settings from /etc/resolv.conf and fallback to root hints.
If letsdane is compiled with libunbound, all queries are DNSSEC validated with a hardcoded ICANN 2017 KSK (you can set trust anchor file by setting -anchor option)
Use letsdane -help to see command line options.
Let's DANE now supports Happy Eyeballs v2 for faster connection establishment in dual-stack environments. This feature is opt-in and can be enabled via environment variables.
To enable Happy Eyeballs, set the following environment variable:
export LETSDANE_HAPPY_EYEBALLS=true
letsdane -r 1.1.1.1Happy Eyeballs can be configured using the following environment variables:
LETSDANE_HAPPY_EYEBALLS- Enable/disable Happy Eyeballs (default:false)LETSDANE_HE_RESOLUTION_DELAY- DNS resolution delay in milliseconds to prefer IPv6 (default:50)LETSDANE_HE_CONNECTION_DELAY- Connection attempt delay in milliseconds (default:250, min:100, max:2000)LETSDANE_HE_METRICS- Enable/disable metrics logging (default:truewhen Happy Eyeballs is enabled)LETSDANE_HE_VERBOSE- Enable verbose debugging output (default:false)LETSDANE_HE_METRICS_DB- Enable storing metrics to Supabase database (default:false)
export LETSDANE_HAPPY_EYEBALLS=true
export LETSDANE_HE_RESOLUTION_DELAY=100
export LETSDANE_HE_CONNECTION_DELAY=300
export LETSDANE_HE_METRICS=true
export LETSDANE_HE_VERBOSE=false
letsdane -r 1.1.1.1When Happy Eyeballs is enabled, connection metrics are automatically logged, showing:
- DNS resolution timing for IPv4 and IPv6
- Connection attempt outcomes for each address
- Which address family (IPv4 or IPv6) wins the connection race
- Performance statistics for monitoring IPv6 adoption
To disable metrics logging:
export LETSDANE_HAPPY_EYEBALLS=true
export LETSDANE_HE_METRICS=false
letsdane -r 1.1.1.1Metrics can optionally be stored in a Supabase database for long-term analysis. To enable database storage, set the following environment variables:
export LETSDANE_HAPPY_EYEBALLS=true
export LETSDANE_HE_METRICS_DB=true
export SUPABASE_URL=your-supabase-url
export SUPABASE_ANON_KEY=your-supabase-anon-key
letsdane -r 1.1.1.1Happy Eyeballs v2 implements the following algorithm:
- DNS queries for both IPv6 (AAAA) and IPv4 (A) records are sent with a small delay (default 50ms) to prefer IPv6
- Addresses are sorted and interleaved to alternate between IPv6 and IPv4
- Connection attempts are staggered with configurable delays (default 250ms)
- The first successful connection wins; other attempts are cancelled
- DANE and DNSSEC validation are preserved throughout the process
This reduces connection latency in dual-stack environments while maintaining security guarantees.
- danectl: https://raf.org/danectl (helper tool for certbot & letsencrypt)
- other: https://www.huque.com/pages/tools.html (various DANE tools)
To build a Docker image run:
git clone https://github.com/buffrr/letsdane
cd letsdane && docker build -t letsdane .
To start a container with proxy on port 8080 with certs in the dane directory run:
docker run --name letsdane -dp 127.0.0.1:8080:8080 \
-v "$(pwd)"/dane:/root/.letsdane \
--restart unless-stopped \
letsdane -verbose
The proxy is intended to be installed locally on your machine, and the generated CA should only be used on that machine. letsdane assumes that your user account is secure (even without letsdane, your user account must not be compromised to be able to use a browser securely)
letsdane uses libunbound to validate DNSSEC, so you don't need to trust any dns provider.
If you already have a local DNSSEC capable resolver, and you don't want letsdane to validate dnssec for you,
you can use -skip-dnssec (you should know what you're doing because this can be dangerous!)
If you use -skip-dnssec, letsdane will use the Authenticated Data flag.
I wanted to try DANE, but no browser currently supports it. It may still be a long way to go for browser support, but if you want to try it now you can!
Contributions are welcome!
Thanks to the awesome miekg/dns package.
Even though TLS proxies are not new, the GNU Naming System has prior art on this since they also use a TLS proxy to make their domains work in other applications, but their naming system is very different from traditional DNS.
