Repository navigation
Release v0.6.1
SafeDNS v0.6.1
π Bug Fixes
-
Fixed stats always showing zero β
getStats,clearStats, andclearCache
were deadlocking the tokio runtime by callingblock_onfrom a JNI thread while
the runtime was already executing the proxy. SwitchedGLOBAL_STATSand
GLOBAL_CACHEfromtokio::sync::RwLocktostd::sync::RwLockso JNI threads
can read stats without touching the async runtime. -
Fixed Android system DNS cache bypassing the proxy β Android was caching DNS
responses with their original TTLs and serving repeat queries itself, so the proxy
cache never got a second chance to hit. All responses now have their TTLs zeroed
before being handed back to Android, forcing every lookup through the proxy while
the proxy's own cache (with real TTLs) serves them instantly. -
Fixed hardcoded DNS transaction ID in heartbeat β heartbeat queries always
used0x1234, causing response collisions when multiple packets were in-flight. -
Fixed rustls-webpki vulnerability (RUSTSEC-2026-0049) β CRLs not considered
authoritative by Distribution Point due to faulty matching logic. Pinned
rustls-webpkito>=0.103.10across the entire dependency tree (reqwest,
rustls, rustls-platform-verifier, quinn). -
Replaced unmaintained
daemonizecrate (RUSTSEC-2025-0069) β reimplemented
as a POSIX double-fork usingnixwhich is already a required CLI dependency.
Behaviour is identical: double-fork + setsid + chdir/tmp+ umask0o022.
β‘ Performance
-
Single persistent DNS socket β replaced the fixed 8-thread executor and
per-queryDatagramSocketcreation with one shared protected socket,
demultiplexed by transaction ID viaConcurrentHashMap<Short, CompletableDeferred>.
Eliminates socket creation overhead on every DNS query. -
16-shard DNS cache β the cache
HashMapis now split into 16 independent
shards using FNV-1a hashing. Concurrent queries hashing to different shards never
block each other, reducing lock contention ~16x under load. -
In-flight deduplication β concurrent queries for the same domain (the classic
simultaneous A + AAAA lookup) now share a single DoH fetch. The first query
fetches and broadcasts the result; waiters receive it instantly with zero extra
upstream requests. -
Negative caching β NXDOMAIN and NODATA responses (e.g. "does this domain have
AAAA records?") are now cached using the SOA minimum TTL from the authority
section. Previously these always went upstream.
β¨ Improvements
-
Suffix-based cache exclusion β
exclude_domain(single exact match) replaced
withexclude_suffixes(comma-separated suffix list)."every1dns.net"now
automatically excludes all UUID-prefixed subdomains like
8f3aβ¦b4e3.is-doh.help.every1dns.netwithout listing each one. -
Heartbeat no longer pollutes logs and stats β the heartbeat now sends a direct
HTTPS HEAD request to the DoH resolver URL instead of fake DNS wire packets. This
means heartbeat activity never appears in the query log or inflates the stats
counters.constructDnsQueryremoved. -
Network change recovery β the proxy backend now automatically restarts when
Android reports a new network (WiFi β mobile, reconnect after drop), triggering a
fresh bootstrap DNS resolution against the new interface. -
Cache miss counter β stats now track cache misses separately alongside hits.
The StatsScreen shows a live Cache Hit Rate progress bar
(hits / (hits + misses)), colour-coded green β₯60%, yellow β₯30%, red below.
Cache stored entry count also displayed. -
Clean log thread shutdown β
stopProxy()now sends aShutdownsentinel to
the native log thread, allowing it to exit cleanly instead of leaking on service
stop. -
Flattened log sender code β the 8-level nested
if let Okpyramid in the JNI
log forwarder replaced with a flat|| -> Option<()>closure. -
Play Store compliance β
QUERY_ALL_PACKAGESpermission removed. Replaced with
a targeted<queries>intent filter (CATEGORY_LAUNCHER) which achieves the same
result for the app exclusion screen without requiring broad package visibility
justification.
Full Changelog: v0.6.0...v0.6.1