Skip to content

Commit d83d029

Browse files
committed
Refactor WG endpoint setup with role-based proxy activation
Move wgProxy.Work() and wgConfigWorkaround() into EndpointUpdater to centralize the timing of proxy activation relative to WireGuard peer updates. The initiator calls Work() before updating the peer (so the proxy is ready for the immediate handshake), while the responder calls Work() after (to avoid premature activation). Add SwitchWGEndpoint for relay fallback on ICE disconnect, which skips the initiator/responder distinction since WireGuard roaming wil overwrite the endpoint regardless.
1 parent 7bc8510 commit d83d029

File tree

4 files changed

+69
-35
lines changed

4 files changed

+69
-35
lines changed

client/internal/peer/conn.go

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -385,19 +385,14 @@ func (conn *Conn) onICEConnectionIsReady(priority conntype.ConnPriority, iceConn
385385
conn.wgProxyRelay.Pause()
386386
}
387387

388-
if wgProxy != nil {
389-
wgProxy.Work()
390-
}
391-
392388
conn.Log.Infof("configure WireGuard endpoint to: %s", ep.String())
393389
conn.enableWgWatcherIfNeeded()
394390

395391
presharedKey := conn.presharedKey(iceConnInfo.RosenpassPubKey)
396-
if err = conn.endpointUpdater.ConfigureWGEndpoint(ep, presharedKey); err != nil {
392+
if err = conn.endpointUpdater.ConfigureWGEndpoint(ep, presharedKey, wgProxy); err != nil {
397393
conn.handleConfigurationFailure(err, wgProxy)
398394
return
399395
}
400-
wgConfigWorkaround()
401396

402397
if conn.wgProxyRelay != nil {
403398
conn.Log.Debugf("redirect packets from relayed conn to WireGuard")
@@ -430,14 +425,10 @@ func (conn *Conn) onICEStateDisconnected() {
430425
if conn.isReadyToUpgrade() {
431426
conn.Log.Infof("ICE disconnected, set Relay to active connection")
432427
conn.dumpState.SwitchToRelay()
433-
conn.wgProxyRelay.Work()
434-
435428
presharedKey := conn.presharedKey(conn.rosenpassRemoteKey)
436-
if err := conn.endpointUpdater.ConfigureWGEndpoint(conn.wgProxyRelay.EndpointAddr(), presharedKey); err != nil {
429+
if err := conn.endpointUpdater.SwitchWGEndpoint(conn.wgProxyRelay.EndpointAddr(), presharedKey, conn.wgProxyRelay); err != nil {
437430
conn.Log.Errorf("failed to switch to relay conn: %v", err)
438431
}
439-
440-
conn.wgProxyRelay.Work()
441432
conn.currentConnPriority = conntype.Relay
442433
} else {
443434
conn.Log.Infof("ICE disconnected, do not switch to Relay. Reset priority to: %s", conntype.None.String())
@@ -499,20 +490,15 @@ func (conn *Conn) onRelayConnectionIsReady(rci RelayConnInfo) {
499490
return
500491
}
501492

502-
wgProxy.Work()
503-
presharedKey := conn.presharedKey(rci.rosenpassPubKey)
504-
505493
conn.enableWgWatcherIfNeeded()
506494

507-
if err := conn.endpointUpdater.ConfigureWGEndpoint(wgProxy.EndpointAddr(), presharedKey); err != nil {
495+
if err := conn.endpointUpdater.ConfigureWGEndpoint(wgProxy.EndpointAddr(), conn.presharedKey(rci.rosenpassPubKey), wgProxy); err != nil {
508496
if err := wgProxy.CloseConn(); err != nil {
509497
conn.Log.Warnf("Failed to close relay connection: %v", err)
510498
}
511499
conn.Log.Errorf("Failed to update WireGuard peer configuration: %v", err)
512500
return
513501
}
514-
515-
wgConfigWorkaround()
516502
conn.rosenpassRemoteKey = rci.rosenpassPubKey
517503
conn.currentConnPriority = conntype.Relay
518504
conn.statusRelay.SetConnected()
@@ -862,9 +848,3 @@ func isController(config ConnConfig) bool {
862848
func isRosenpassEnabled(remoteRosenpassPubKey []byte) bool {
863849
return remoteRosenpassPubKey != nil
864850
}
865-
866-
// wgConfigWorkaround is a workaround for the issue with WireGuard configuration update
867-
// When update a peer configuration in near to each other time, the second update can be ignored by WireGuard
868-
func wgConfigWorkaround() {
869-
time.Sleep(100 * time.Millisecond)
870-
}

client/internal/peer/endpoint.go

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88

99
"github.com/sirupsen/logrus"
1010
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
11+
12+
"github.com/netbirdio/netbird/client/iface/wgproxy"
1113
)
1214

1315
const (
@@ -37,25 +39,36 @@ func NewEndpointUpdater(log *logrus.Entry, wgConfig WgConfig, initiator bool) *E
3739
// ConfigureWGEndpoint sets up the WireGuard endpoint configuration.
3840
// The initiator immediately configures the endpoint, while the non-initiator
3941
// waits for a fallback period before configuring to avoid handshake congestion.
40-
func (e *EndpointUpdater) ConfigureWGEndpoint(addr *net.UDPAddr, presharedKey *wgtypes.Key) error {
42+
//
43+
// If wgProxy is non-nil, Work() is called at the correct time relative to the
44+
// WireGuard peer update: before for the initiator (so the proxy is ready to
45+
// process the immediate handshake) and after for the non-initiator.
46+
func (e *EndpointUpdater) ConfigureWGEndpoint(addr *net.UDPAddr, presharedKey *wgtypes.Key, wgProxy wgproxy.Proxy) error {
4147
e.mu.Lock()
4248
defer e.mu.Unlock()
4349

4450
if e.initiator {
45-
e.log.Debugf("configure up WireGuard as initiatr")
46-
return e.updateWireGuardPeer(addr, presharedKey)
51+
e.log.Debugf("configure up WireGuard as initiator")
52+
return e.configureAsInitiator(addr, presharedKey, wgProxy)
4753
}
4854

55+
e.log.Debugf("configure up WireGuard as responder")
56+
return e.configureAsResponder(addr, presharedKey, wgProxy)
57+
}
58+
59+
func (e *EndpointUpdater) SwitchWGEndpoint(addr *net.UDPAddr, presharedKey *wgtypes.Key, wgProxy wgproxy.Proxy) error {
60+
e.mu.Lock()
61+
defer e.mu.Unlock()
62+
4963
// prevent to run new update while cancel the previous update
5064
e.waitForCloseTheDelayedUpdate()
5165

52-
var ctx context.Context
53-
ctx, e.cancelFunc = context.WithCancel(context.Background())
54-
e.updateWg.Add(1)
55-
go e.scheduleDelayedUpdate(ctx, addr, presharedKey)
66+
// Makes no sense to distinguish initiator and responder because the roaming feature in WG will overwrite the endpoint
67+
if wgProxy != nil {
68+
wgProxy.Work()
69+
}
5670

57-
e.log.Debugf("configure up WireGuard and wait for handshake")
58-
return e.updateWireGuardPeer(nil, presharedKey)
71+
return e.updateWireGuardPeer(addr, presharedKey)
5972
}
6073

6174
func (e *EndpointUpdater) RemoveWgPeer() error {
@@ -66,6 +79,41 @@ func (e *EndpointUpdater) RemoveWgPeer() error {
6679
return e.wgConfig.WgInterface.RemovePeer(e.wgConfig.RemoteKey)
6780
}
6881

82+
func (e *EndpointUpdater) configureAsInitiator(addr *net.UDPAddr, presharedKey *wgtypes.Key, wgProxy wgproxy.Proxy) error {
83+
if wgProxy != nil {
84+
wgProxy.Work()
85+
}
86+
87+
if err := e.updateWireGuardPeer(addr, presharedKey); err != nil {
88+
return err
89+
}
90+
91+
wgConfigWorkaround()
92+
return nil
93+
}
94+
95+
func (e *EndpointUpdater) configureAsResponder(addr *net.UDPAddr, presharedKey *wgtypes.Key, wgProxy wgproxy.Proxy) error {
96+
// prevent to run new update while cancel the previous update
97+
e.waitForCloseTheDelayedUpdate()
98+
99+
var ctx context.Context
100+
ctx, e.cancelFunc = context.WithCancel(context.Background())
101+
e.updateWg.Add(1)
102+
go e.scheduleDelayedUpdate(ctx, addr, presharedKey)
103+
104+
e.log.Debugf("configure up WireGuard and wait for handshake")
105+
if err := e.updateWireGuardPeer(nil, presharedKey); err != nil {
106+
e.waitForCloseTheDelayedUpdate()
107+
return err
108+
}
109+
wgConfigWorkaround()
110+
111+
if wgProxy != nil {
112+
wgProxy.Work()
113+
}
114+
return nil
115+
}
116+
69117
func (e *EndpointUpdater) waitForCloseTheDelayedUpdate() {
70118
if e.cancelFunc == nil {
71119
return
@@ -101,3 +149,9 @@ func (e *EndpointUpdater) updateWireGuardPeer(endpoint *net.UDPAddr, presharedKe
101149
presharedKey,
102150
)
103151
}
152+
153+
// wgConfigWorkaround is a workaround for the issue with WireGuard configuration update
154+
// When update a peer configuration in near to each other time, the second update can be ignored by WireGuard
155+
func wgConfigWorkaround() {
156+
time.Sleep(100 * time.Millisecond)
157+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ require (
4040
github.com/c-robinson/iplib v1.0.3
4141
github.com/caddyserver/certmagic v0.21.3
4242
github.com/cilium/ebpf v0.15.0
43-
github.com/coder/websocket v1.8.13
43+
github.com/coder/websocket v1.8.14
4444
github.com/coreos/go-iptables v0.7.0
4545
github.com/creack/pty v1.1.24
4646
github.com/dexidp/dex v0.0.0-00010101000000-000000000000

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
107107
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
108108
github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
109109
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
110-
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
111-
github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
110+
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
111+
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
112112
github.com/containerd/containerd v1.7.29 h1:90fWABQsaN9mJhGkoVnuzEY+o1XDPbg9BTC9QTAHnuE=
113113
github.com/containerd/containerd v1.7.29/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs=
114114
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=

0 commit comments

Comments
 (0)