Diagnostic output
sudo /config/dnscrypt-proxy/dnscrypt-proxy -version
2.1.18
What's happening?
Since upgrading from v2.1.7 to v2.1.18, I'm seeing a constant stream of OutNoRoutes IPv6 errors on my router (EdgeRouter X running EdgeOS), caused by the new network monitor probing [2001:db8::1]:9 every 5 seconds. On systems that have IPv6 forwarding enabled but no IPv6 default route (very common on IPv4-only ISPs), each probe fails with ENETUNREACH and increments the kernel's ipSystemStatsOutNoRoutes counter.
Environment
- dnscrypt-proxy version: v2.1.18 (upgraded from v2.1.7)
- OS: EdgeOS on EdgeRouter X
- IPv6: forwarding enabled (
net.ipv6.conf.all.forwarding = 1), but no IPv6 default route and no IPv6 internet connectivity
- Config:
ipv6_servers = false, block_ipv6 = true, listen_addresses = ['[::]:5353']
The problem
The new network monitor introduced in netmon.go calls discoverNetworkMonitorLocalIPs() every 5 seconds (defaultNetworkMonitorInterval), which performs a UDP "dial" to two probe addresses to discover the local IP:
// netmon.go
probeAddrs := []string{"192.0.2.1:9", "[2001:db8::1]:9"}
On a system without an IPv6 default route, the net.DialTimeout("udp", "[2001:db8::1]:9", 1s) call fails immediately with ENETUNREACH. The kernel counts this as an OutNoRoutes event on the IPv6 stats.
This happens every 5 seconds, forever, generating a constant ~0.2 NoRoutes/s that never stops — even when dnscrypt-proxy is otherwise idle and no user queries are being made.
Steps to reproduce
- Set up a Linux system with IPv6 forwarding enabled but no IPv6 default route:
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
ip -6 route show default # should be empty
- Start dnscrypt-proxy v2.1.18 with any config (the issue is independent of config).
- Monitor the kernel IPv6 NoRoutes counter:
# Using SNMP stats or /proc/net/snmp6:
watch -n 1 'grep OutNoRoutes /proc/net/snmp6'
- Observe the counter increasing by ~1 every 5 seconds, constantly, with no DNS queries being made.
Evidence
I noticed the issue via SNMP monitoring (VictoriaMetrics scraping the router's ipSystemStatsOutNoRoutes counter). The rate is rock-steady at exactly 0.2/s (= 1 probe / 5 seconds), which matches the defaultNetworkMonitorInterval:
| Time window |
OutNoRoutes IPv6 rate |
| Before v2.1.18 upgrade |
~0.003/s (baseline noise) |
| After v2.1.18 upgrade |
0.20/s constant |
The rate does not correlate with DNS query volume, LAN traffic, or time of day — it's a fixed 1 probe every 5 seconds, confirming it's the network monitor and not user traffic.
A tcpdump on the router confirms dnscrypt-proxy itself is not sending any IPv6 DNS traffic (all queries are IPv4/UDP to the upstream resolvers). The NoRoutes are purely from the internal probe.
Impact
- Pollutes the kernel IPv6 stats with noise, making it harder to spot real routing problems.
- On routers/edge devices monitored via SNMP, this triggers false-positive alerts on "IPv6 NoRoute" counters.
- The probe serves no useful purpose on a system with no IPv6 connectivity — it will always fail, every 5 seconds, forever.
Expected behavior
The network monitor should avoid (or skip) the IPv6 probe when the system has no IPv6 default route. A few possible approaches:
- Check for an IPv6 default route before probing — if
ip -6 route show default is empty (or ::/0 is not in the routing table), skip the [2001:db8::1]:9 probe.
- Cache the probe failure — if the IPv6 probe fails with
ENETUNREACH / EHOSTUNREACH, back off and retry much less frequently (or not at all) instead of hammering it every 5 seconds.
- Make the IPv6 probe opt-in — only probe IPv6 if
ipv6_servers = true or if IPv6 connectivity is detected.
- Catch and ignore
ENETUNREACH — at minimum, don't let the failed probe increment kernel stats (though this may not be controllable from userspace).
Suggested fix (rough idea)
In discoverNetworkMonitorLocalIPs(), something like:
probeAddrs := []string{"192.0.2.1:9"}
// Only add IPv6 probe if the system has an IPv6 default route
if hasIPv6DefaultRoute() {
probeAddrs = append(probeAddrs, "[2001:db8::1]:9")
}
Or, in networkMonitor.check(), if the IPv6 probe has failed N times in a row with a network-unreachable error, stop including it in the fingerprint until a network change is detected.
Made the AI write this so clarify the issue in depth after some hours trying to find unrelated case, so it's verified by me (yeah IA made it verbose as always but extra info doesn't hurt).
Happy to test a patch if needed. Thanks for the great work on dnscrypt-proxy!
Diagnostic output
What's happening?
Since upgrading from v2.1.7 to v2.1.18, I'm seeing a constant stream of
OutNoRoutesIPv6 errors on my router (EdgeRouter X running EdgeOS), caused by the new network monitor probing[2001:db8::1]:9every 5 seconds. On systems that have IPv6 forwarding enabled but no IPv6 default route (very common on IPv4-only ISPs), each probe fails withENETUNREACHand increments the kernel'sipSystemStatsOutNoRoutescounter.Environment
net.ipv6.conf.all.forwarding = 1), but no IPv6 default route and no IPv6 internet connectivityipv6_servers = false,block_ipv6 = true,listen_addresses = ['[::]:5353']The problem
The new network monitor introduced in
netmon.gocallsdiscoverNetworkMonitorLocalIPs()every 5 seconds (defaultNetworkMonitorInterval), which performs a UDP "dial" to two probe addresses to discover the local IP:On a system without an IPv6 default route, the
net.DialTimeout("udp", "[2001:db8::1]:9", 1s)call fails immediately withENETUNREACH. The kernel counts this as anOutNoRoutesevent on the IPv6 stats.This happens every 5 seconds, forever, generating a constant ~0.2 NoRoutes/s that never stops — even when dnscrypt-proxy is otherwise idle and no user queries are being made.
Steps to reproduce
Evidence
I noticed the issue via SNMP monitoring (VictoriaMetrics scraping the router's
ipSystemStatsOutNoRoutescounter). The rate is rock-steady at exactly 0.2/s (= 1 probe / 5 seconds), which matches thedefaultNetworkMonitorInterval:The rate does not correlate with DNS query volume, LAN traffic, or time of day — it's a fixed 1 probe every 5 seconds, confirming it's the network monitor and not user traffic.
A
tcpdumpon the router confirms dnscrypt-proxy itself is not sending any IPv6 DNS traffic (all queries are IPv4/UDP to the upstream resolvers). The NoRoutes are purely from the internal probe.Impact
Expected behavior
The network monitor should avoid (or skip) the IPv6 probe when the system has no IPv6 default route. A few possible approaches:
ip -6 route show defaultis empty (or::/0is not in the routing table), skip the[2001:db8::1]:9probe.ENETUNREACH/EHOSTUNREACH, back off and retry much less frequently (or not at all) instead of hammering it every 5 seconds.ipv6_servers = trueor if IPv6 connectivity is detected.ENETUNREACH— at minimum, don't let the failed probe increment kernel stats (though this may not be controllable from userspace).Suggested fix (rough idea)
In
discoverNetworkMonitorLocalIPs(), something like:Or, in
networkMonitor.check(), if the IPv6 probe has failed N times in a row with a network-unreachable error, stop including it in the fingerprint until a network change is detected.Made the AI write this so clarify the issue in depth after some hours trying to find unrelated case, so it's verified by me (yeah IA made it verbose as always but extra info doesn't hurt).
Happy to test a patch if needed. Thanks for the great work on dnscrypt-proxy!