LanRouted, LanDenied and LanWithdrawn sit beside the probe counters on the
same struct: a hub's peer-LAN routing is counted where every other service
counter lives, and where the API and the stats view already read from.
A running tun entrypoint cannot tell a dead device fd from an idle link: both look like frozen stats. The probe writes a self-addressed IPv4/UDP packet (spokeIP->spokeIP, magic+seq) into the device every 30s and reads it back on its own bound socket; sent/acked deltas go to the caller through the metadata probeReport callback. Enabled by metadata probe (default off, gost path unchanged); new probeSent/probeAcked counters (101/102) in x stats.
- WrapUDPConn, WrapPacketConn, WrapListener: add nil guards for pc/ln params
- NewGRPCPlugin: return no-op observer instead of nil on connection error
- gRPC plugin: fix resource leak by wiring Close() through observerWrapper
and service.Close() lifecycle
- Both plugins: log unknown event types instead of silently dropping them
- httpPlugin: remove dead nil check for always-non-nil client field
- Stats.Reset: update core interface doc to match implementation behavior
- Add doc comments to all exported symbols across the observer package