Skip to content

[Tech-debt] kill -0 readiness check doesn't prove proxy bound port 53 (#156 F3) #159

Description

@flyhigher139

Context

PR #156 added a post-launch kill -0 $PROXY_PID check to enable_dns_mode's privileged shell script to detect early proxy death (the silent-failure path from #155). After 1 second, if kill -0 succeeds, the script proceeds to networksetup -setdnsservers <iface> 127.0.0.1.

Problem: kill -0 proves the process exists, not that it's listening on UDP 53. The proxy could be:

  • Alive but in pre-UdpSocket::bind initialization code
  • Hung at bind (port already in use; bind blocks on certain error paths in tokio::net::UdpSocket::bind)
  • Mid-panic during startup before taking the bind
  • Delayed by a slow filesystem / extension-loading step

In any of these, kill -0 returns 0, the script clears the readiness check, and networksetup flips system DNS to 127.0.0.1. The DNS client queries 127.0.0.1:53, gets no response, and we're back to the same black-hole port the PR claims to eliminate — just with a smaller window than before.

The exact "binary missing" path is already caught by the [ ! -x ] early check, so kill -0 only adds value if we also verify bind completion.

Residual risk today

On normal macOS systems the window is sub-second and worst-case is one query timeout. On systems where bind is slow (full disk, encrypted FS, process spawn contention), the window grows. There's no upper bound guarantee from kill -0 alone.

Fix

Add a proxy-emitted readiness signal:

  1. Proxy side (crates/mhost-dns/src/bin/dns_proxy.rs or proxy.rs::run): after the successful UdpSocket::bind(listen_addr) and before entering the main recv loop, write a small marker file (e.g. runtime_dir()/mhost-dns-proxy-ready.signal) atomically with content "ready\n" and sync_all. Sync matters here: the script's cat / [ -f ] will hit the inode but readers should see the data.

  2. Script side: poll both kill -0 and [ -f "$ready_marker" ] with a bounded timeout (e.g. 5s with 100ms intervals). Either failure aborts the script via the existing error path.

  3. Cleanup side: disable_dns_mode already cleans runtime_dir() on success; ensure the ready marker is removed alongside. If the proxy dies abnormally, the marker becomes stale — cleanup_stale_proxy should remove it during the next start-up scan.

UDP probe as alternative: connect a UDP socket to 127.0.0.1:53 + send a no-op. Not reliable for unconnected UDP (kernel queues the datagram without confirming a listener). Marker is preferred.

Linked

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdns-modeDNS mode (本地 DNS server) 相关问题

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions