diff --git a/client/internal/engine.go b/client/internal/engine.go index ca93fa482..52912f11e 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -13,6 +13,7 @@ import ( "slices" "strings" "sync" + "sync/atomic" "time" "github.com/pion/ice/v3" @@ -122,7 +123,8 @@ type Engine struct { // STUNs is a list of STUN servers used by ICE STUNs []*stun.URI // TURNs is a list of STUN servers used by ICE - TURNs []*stun.URI + TURNs []*stun.URI + stunTurn atomic.Value // clientRoutes is the most recent list of clientRoutes received from the Management Service clientRoutes route.HAMap @@ -535,6 +537,11 @@ func (e *Engine) handleSync(update *mgmProto.SyncResponse) error { return err } + var stunTurn []*stun.URI + stunTurn = append(stunTurn, e.STUNs...) + stunTurn = append(stunTurn, e.TURNs...) + e.stunTurn.Store(stunTurn) + // todo update signal } @@ -961,11 +968,6 @@ func (e *Engine) connWorker(conn *peer.Conn, peerKey string) { continue } - // we might have received new STUN and TURN servers meanwhile, so update them - e.syncMsgMux.Lock() - conn.UpdateStunTurn(append(e.STUNs, e.TURNs...)) - e.syncMsgMux.Unlock() - err := conn.Open(e.ctx) if err != nil { log.Debugf("connection to peer %s failed: %v", peerKey, err) @@ -989,9 +991,6 @@ func (e *Engine) peerExists(peerKey string) bool { func (e *Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, error) { log.Debugf("creating peer connection %s", pubKey) - var stunTurn []*stun.URI - stunTurn = append(stunTurn, e.STUNs...) - stunTurn = append(stunTurn, e.TURNs...) wgConfig := peer.WgConfig{ RemoteKey: pubKey, @@ -1024,19 +1023,21 @@ func (e *Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, e // randomize connection timeout timeout := time.Duration(rand.Intn(PeerConnectionTimeoutMax-PeerConnectionTimeoutMin)+PeerConnectionTimeoutMin) * time.Millisecond config := peer.ConnConfig{ - Key: pubKey, - LocalKey: e.config.WgPrivateKey.PublicKey().String(), - StunTurn: stunTurn, - InterfaceBlackList: e.config.IFaceBlackList, - DisableIPv6Discovery: e.config.DisableIPv6Discovery, - Timeout: timeout, - UDPMux: e.udpMux.UDPMuxDefault, - UDPMuxSrflx: e.udpMux, - WgConfig: wgConfig, - LocalWgPort: e.config.WgPort, - NATExternalIPs: e.parseNATExternalIPMappings(), - RosenpassPubKey: e.getRosenpassPubKey(), - RosenpassAddr: e.getRosenpassAddr(), + Key: pubKey, + LocalKey: e.config.WgPrivateKey.PublicKey().String(), + Timeout: timeout, + WgConfig: wgConfig, + LocalWgPort: e.config.WgPort, + RosenpassPubKey: e.getRosenpassPubKey(), + RosenpassAddr: e.getRosenpassAddr(), + ICEConfig: peer.ICEConfig{ + StunTurn: &e.stunTurn, + InterfaceBlackList: e.config.IFaceBlackList, + DisableIPv6Discovery: e.config.DisableIPv6Discovery, + UDPMux: e.udpMux.UDPMuxDefault, + UDPMuxSrflx: e.udpMux, + NATExternalIPs: e.parseNATExternalIPMappings(), + }, } peerConn, err := peer.NewConn(config, e.statusRecorder, e.wgProxyFactory, e.mobileDep.TunAdapter, e.mobileDep.IFaceDiscover) diff --git a/client/internal/peer/conn.go b/client/internal/peer/conn.go index d1fe0d419..7c3b60011 100644 --- a/client/internal/peer/conn.go +++ b/client/internal/peer/conn.go @@ -7,6 +7,7 @@ import ( "runtime" "strings" "sync" + "sync/atomic" "time" "github.com/pion/ice/v3" @@ -41,37 +42,41 @@ type WgConfig struct { PreSharedKey *wgtypes.Key } -// ConnConfig is a peer Connection configuration -type ConnConfig struct { - - // Key is a public key of a remote peer - Key string - // LocalKey is a public key of a local peer - LocalKey string - +type ICEConfig struct { // StunTurn is a list of STUN and TURN URLs - StunTurn []*stun.URI + StunTurn *atomic.Value // []*stun.URI // InterfaceBlackList is a list of machine interfaces that should be filtered out by ICE Candidate gathering // (e.g. if eth0 is in the list, host candidate of this interface won't be used) InterfaceBlackList []string DisableIPv6Discovery bool + UDPMux ice.UDPMux + UDPMuxSrflx ice.UniversalUDPMux + + NATExternalIPs []string +} + +// ConnConfig is a peer Connection configuration +type ConnConfig struct { + // Key is a public key of a remote peer + Key string + // LocalKey is a public key of a local peer + LocalKey string + Timeout time.Duration WgConfig WgConfig - UDPMux ice.UDPMux - UDPMuxSrflx ice.UniversalUDPMux - LocalWgPort int - NATExternalIPs []string - // RosenpassPubKey is this peer's Rosenpass public key RosenpassPubKey []byte // RosenpassPubKey is this peer's RosenpassAddr server address (IP:port) RosenpassAddr string + + // ICEConfig ICE protocol configuration + ICEConfig ICEConfig } // OfferAnswer represents a session establishment offer or answer @@ -146,11 +151,6 @@ func (conn *Conn) WgConfig() WgConfig { return conn.config.WgConfig } -// UpdateStunTurn update the turn and stun addresses -func (conn *Conn) UpdateStunTurn(turnStun []*stun.URI) { - conn.config.StunTurn = turnStun -} - // NewConn creates a new not opened Conn to the remote peer. // To establish a connection run Conn.Open func NewConn(config ConnConfig, statusRecorder *Status, wgProxyFactory *wgproxy.Factory, adapter iface.TunAdapter, iFaceDiscover stdnet.ExternalIFaceDiscover) (*Conn, error) { @@ -187,20 +187,20 @@ func (conn *Conn) reCreateAgent() error { agentConfig := &ice.AgentConfig{ MulticastDNSMode: ice.MulticastDNSModeDisabled, NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4, ice.NetworkTypeUDP6}, - Urls: conn.config.StunTurn, + Urls: conn.config.ICEConfig.StunTurn.Load().([]*stun.URI), CandidateTypes: conn.candidateTypes(), FailedTimeout: &failedTimeout, - InterfaceFilter: stdnet.InterfaceFilter(conn.config.InterfaceBlackList), - UDPMux: conn.config.UDPMux, - UDPMuxSrflx: conn.config.UDPMuxSrflx, - NAT1To1IPs: conn.config.NATExternalIPs, + InterfaceFilter: stdnet.InterfaceFilter(conn.config.ICEConfig.InterfaceBlackList), + UDPMux: conn.config.ICEConfig.UDPMux, + UDPMuxSrflx: conn.config.ICEConfig.UDPMuxSrflx, + NAT1To1IPs: conn.config.ICEConfig.NATExternalIPs, Net: transportNet, DisconnectedTimeout: &iceDisconnectedTimeout, KeepaliveInterval: &iceKeepAlive, RelayAcceptanceMinWait: &iceRelayAcceptanceMinWait, } - if conn.config.DisableIPv6Discovery { + if conn.config.ICEConfig.DisableIPv6Discovery { agentConfig.NetworkTypes = []ice.NetworkType{ice.NetworkTypeUDP4} } @@ -480,7 +480,7 @@ func (conn *Conn) punchRemoteWGPort(pair *ice.CandidatePair, remoteWgPort int) { return } - mux, ok := conn.config.UDPMuxSrflx.(*bind.UniversalUDPMuxDefault) + mux, ok := conn.config.ICEConfig.UDPMuxSrflx.(*bind.UniversalUDPMuxDefault) if !ok { log.Warn("invalid udp mux conversion") return diff --git a/client/internal/peer/conn_test.go b/client/internal/peer/conn_test.go index b608a5929..c124208d1 100644 --- a/client/internal/peer/conn_test.go +++ b/client/internal/peer/conn_test.go @@ -7,7 +7,6 @@ import ( "time" "github.com/magiconair/properties/assert" - "github.com/pion/stun/v2" "github.com/netbirdio/netbird/client/internal/stdnet" "github.com/netbirdio/netbird/client/internal/wgproxy" @@ -15,12 +14,13 @@ import ( ) var connConf = ConnConfig{ - Key: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=", - LocalKey: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=", - StunTurn: []*stun.URI{}, - InterfaceBlackList: nil, - Timeout: time.Second, - LocalWgPort: 51820, + Key: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=", + LocalKey: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=", + Timeout: time.Second, + LocalWgPort: 51820, + ICEConfig: ICEConfig{ + InterfaceBlackList: nil, + }, } func TestNewConn_interfaceFilter(t *testing.T) { diff --git a/client/internal/peer/stdnet.go b/client/internal/peer/stdnet.go index 13f5886f5..1faa30ce3 100644 --- a/client/internal/peer/stdnet.go +++ b/client/internal/peer/stdnet.go @@ -7,5 +7,5 @@ import ( ) func (conn *Conn) newStdNet() (*stdnet.Net, error) { - return stdnet.NewNet(conn.config.InterfaceBlackList) + return stdnet.NewNet(conn.config.ICEConfig.InterfaceBlackList) } diff --git a/client/internal/peer/stdnet_android.go b/client/internal/peer/stdnet_android.go index 8a2454371..90865242b 100644 --- a/client/internal/peer/stdnet_android.go +++ b/client/internal/peer/stdnet_android.go @@ -3,5 +3,5 @@ package peer import "github.com/netbirdio/netbird/client/internal/stdnet" func (conn *Conn) newStdNet() (*stdnet.Net, error) { - return stdnet.NewNetWithDiscover(conn.iFaceDiscover, conn.config.InterfaceBlackList) + return stdnet.NewNetWithDiscover(conn.iFaceDiscover, conn.config.ICEConfig.InterfaceBlackList) }