TL;DR

  • Three of four UDP listeners had stopped reading after roughly 17 hours, so about three quarters of plain-DNS queries were discarded in the kernel. DoH, DoT and DoQ were unaffected throughout and the unit stayed active (running).
  • The loop exits on any read error and never closes its socket. A bound socket with no reader stays in the SO_REUSEPORT group, so the kernel goes on delivering its share to a buffer nobody drains. Closing it would have removed it from the group instead.
  • One of the two error classes logs at debug level, which is off by default, and nothing increments a counter. No health check could tell "listener dead" from "quiet period".
  • Reported as dnsproxy issue 525 on 13 September, with the code path, the measurements and a reproduction. Open, labelled P4, no comments as of today.

We cannot say which read error triggered the exit, because nothing logged it - which is the report. Semaphore exhaustion, shutdown and a suppressed log line were each ruled out; what remains is the read-error branch, most plausibly the one that logs at debug level. The fix distinguishes timeouts, deliberate shutdown and everything else, retires a failed socket rather than abandoning it, and logs the exit unconditionally.

The write-up, with the kernel-side checks and a 60-second reproduction that discarded 49,993 of 50,000 datagrams, is running, and answering nothing.