mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-21 21:09:07 +02:00
Only the controller's offer carries KEM material, so when the responder starts a negotiation the controller is meant to reply with its own KEM offer. It only did so before the very first exchange: once it held a converged PSK it answered the responder's offer normally and kept that PSK, on the assumption that a stale key would heal through the WireGuard watcher reconnecting over Signal. That assumption fails when the reconnect comes from the responder. If every answer of a data-path rotation is lost, the responder commits the new PSK and the controller does not, so WireGuard cannot handshake and no further rotation runs to escalate. The watcher closes the connection after ~3.5 minutes and ICE reconnects in seconds, but the reconnect offer came from the responder, the controller kept its stale key, and the tunnel stayed down. In the lab it took 201 s and a lazy-connection idle/wake cycle to heal; with lazy connections off, the default, nothing would heal it. Treat a converged exchange as not in flight: a responder offer then always gets a fresh bootstrap, so any responder-started renegotiation re-aligns both PSKs. While the controller's own exchange is still in flight a crossing offer is answered normally as before, so offers cannot multiply. The cost is one extra Signal KEM round per responder-started reconnect.