Skip to content

fix(coord): persist vpn_ip in NVS to survive elided Node.Addresses - #73

Merged
fudio101 merged 1 commit into
mainfrom
fix/vpn-ip-nvs-persistence
Aug 19, 2026
Merged

fix(coord): persist vpn_ip in NVS to survive elided Node.Addresses#73
fudio101 merged 1 commit into
mainfrom
fix/vpn-ip-nvs-persistence

Conversation

@fudio101

Copy link
Copy Markdown
Collaborator

Summary

  • On repeat registration of an already-known node, the control plane can omit Node.Addresses (and HomeDERP) in both RegisterResponse and the initial MapResponse — the client's own VPN IP is assigned once and never changes, so the server just doesn't resend it.
  • vpn_ip only ever lived in RAM with no fallback, so every reboot after the node's first-ever registration silently regressed to 0.0.0.0 while DERP/DISCO/WireGuard kept working fine (none of that traffic depends on the node knowing its own address) — matching the exact symptom in 3.1.0: vpn_ip stays 0.0.0.0 while state=CONNECTED, control-plane last-seen never advances #72 (state=CONNECTED, DERP/DISCO healthy, vpn_ip stuck at 0, Tailscale admin "last seen" never advancing).
  • Fix: persist vpn_ip in the "microlink" NVS namespace (same namespace as the machine/WG/DISCO keys) and restore it as a fallback during init, mirroring the existing ml_peer_nvs.c pattern already used for the peer cache. Save on every site that can set vpn_ip (do_register, the do_fetch_peers MapResponse fallback, and the long-poll update path), gated on the value actually changing.

Closes #72

Test plan

Verified on real hardware (LilyGo T-Display-S3), by pinning a local microlink override into a consumer project and driving two boots:

  • Boot 1 (factory reset → brand-new node): first-ever registration necessarily includes full Node.Addresses → log shows Our VPN IP: 100.105.164.125, DERP connects, 6 peers handshake successfully. Value gets persisted to NVS.
  • Boot 2 (normal reboot, same node): registration reproduces the bug — Node.Addresses and HomeDERP are both omitted again (Home DERP region: 9 (default) fires, no Our VPN IP: line) — but microlink: VPN IP restored from NVS: 100.105.164.125 fires at init, before registration even starts, and vpn_ip stays correct throughout the session (DERP connects, DISCO PONGs succeed, no crashes).
  • Confirmed via log evidence this is not a cert/auth issue: the control-plane channel is Noise-encrypted (no certs involved), DERP TLS connects successfully in both boots, and registration itself succeeds cleanly (Fetching peers... runs, no RegisterResponse error / not authorized) — only the Addresses field is selectively omitted, consistent with delta-style server behavior for a known node.
  • No automated test suite exists for this component (hardware-in-the-loop only, per TESTING_GUIDE.md) — this PR relies on the hardware repro above as the regression check.

🤖 Generated with Claude Code

On repeat registration of an already-known node, the control plane may
omit Node.Addresses in both RegisterResponse and the initial
MapResponse — the client's own VPN IP is only assigned once and never
changes, so the server doesn't resend it. vpn_ip lived only in RAM and
had no fallback, so every reboot after the node's first-ever
registration silently regressed to 0.0.0.0 while DERP/DISCO/WireGuard
kept working fine, since none of that traffic depends on the node
knowing its own address.

Persist vpn_ip in the "microlink" NVS namespace (same as the machine/
WG/DISCO keys) and restore it at init as a fallback, mirroring the
existing ml_peer_nvs.c pattern for the peer cache.

Verified on hardware (LilyGo T-Display-S3): after a factory reset,
first registration captured "Our VPN IP: 100.105.164.125" and
persisted it. A second, non-factory-reset reboot reproduced the bug
(Node.Addresses omitted again on both RegisterResponse and
MapResponse) but vpn_ip stayed 100.105.164.125 throughout, loaded from
NVS before registration even started.

Fixes #72

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@fudio101
fudio101 merged commit 61a1264 into main Aug 19, 2026
14 checks passed
@fudio101
fudio101 deleted the fix/vpn-ip-nvs-persistence branch August 19, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3.1.0: vpn_ip stays 0.0.0.0 while state=CONNECTED, control-plane last-seen never advances

2 participants