mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-30 10:39:08 +02:00
Add wasm client
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
package dns
|
||||
|
||||
func (s *DefaultServer) initialize() (hostManager, error) {
|
||||
return &noopHostConfigurator{}, nil
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type ShutdownState struct{}
|
||||
|
||||
func (s *ShutdownState) Name() string {
|
||||
return "dns_state"
|
||||
}
|
||||
|
||||
func (s *ShutdownState) Cleanup() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ShutdownState) RestoreUncleanShutdownConfigs(context.Context) error {
|
||||
return nil
|
||||
}
|
||||
@@ -450,14 +450,7 @@ func (e *Engine) Start() error {
|
||||
return fmt.Errorf("initialize dns server: %w", err)
|
||||
}
|
||||
|
||||
iceCfg := icemaker.Config{
|
||||
StunTurn: &e.stunTurn,
|
||||
InterfaceBlackList: e.config.IFaceBlackList,
|
||||
DisableIPv6Discovery: e.config.DisableIPv6Discovery,
|
||||
UDPMux: e.udpMux.UDPMuxDefault,
|
||||
UDPMuxSrflx: e.udpMux,
|
||||
NATExternalIPs: e.parseNATExternalIPMappings(),
|
||||
}
|
||||
iceCfg := e.createICEConfig()
|
||||
|
||||
e.connMgr = NewConnMgr(e.config, e.statusRecorder, e.peerStore, wgIface)
|
||||
e.connMgr.Start(e.ctx)
|
||||
@@ -1288,14 +1281,7 @@ func (e *Engine) createPeerConn(pubKey string, allowedIPs []netip.Prefix, agentV
|
||||
Addr: e.getRosenpassAddr(),
|
||||
PermissiveMode: e.config.RosenpassPermissive,
|
||||
},
|
||||
ICEConfig: icemaker.Config{
|
||||
StunTurn: &e.stunTurn,
|
||||
InterfaceBlackList: e.config.IFaceBlackList,
|
||||
DisableIPv6Discovery: e.config.DisableIPv6Discovery,
|
||||
UDPMux: e.udpMux.UDPMuxDefault,
|
||||
UDPMuxSrflx: e.udpMux,
|
||||
NATExternalIPs: e.parseNATExternalIPMappings(),
|
||||
},
|
||||
ICEConfig: e.createICEConfig(),
|
||||
}
|
||||
|
||||
serviceDependencies := peer.ServiceDependencies{
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
//go:build !js
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
icemaker "github.com/netbirdio/netbird/client/internal/peer/ice"
|
||||
)
|
||||
|
||||
// createICEConfig creates ICE configuration for non-WASM environments
|
||||
func (e *Engine) createICEConfig() icemaker.Config {
|
||||
return icemaker.Config{
|
||||
StunTurn: &e.stunTurn,
|
||||
InterfaceBlackList: e.config.IFaceBlackList,
|
||||
DisableIPv6Discovery: e.config.DisableIPv6Discovery,
|
||||
UDPMux: e.udpMux.UDPMuxDefault,
|
||||
UDPMuxSrflx: e.udpMux,
|
||||
NATExternalIPs: e.parseNATExternalIPMappings(),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//go:build js
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
icemaker "github.com/netbirdio/netbird/client/internal/peer/ice"
|
||||
)
|
||||
|
||||
// createICEConfig creates ICE configuration for WASM environment.
|
||||
func (e *Engine) createICEConfig() icemaker.Config {
|
||||
cfg := icemaker.Config{
|
||||
StunTurn: &e.stunTurn,
|
||||
InterfaceBlackList: e.config.IFaceBlackList,
|
||||
DisableIPv6Discovery: e.config.DisableIPv6Discovery,
|
||||
NATExternalIPs: e.parseNATExternalIPMappings(),
|
||||
}
|
||||
|
||||
if e.udpMux != nil {
|
||||
cfg.UDPMux = e.udpMux.UDPMuxDefault
|
||||
cfg.UDPMuxSrflx = e.udpMux
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package networkmonitor
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
||||
)
|
||||
|
||||
func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
|
||||
// No-op for WASM - network changes don't apply
|
||||
return nil
|
||||
}
|
||||
@@ -455,6 +455,14 @@ func (conn *Conn) onRelayConnectionIsReady(rci RelayConnInfo) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if we already have a relay proxy configured
|
||||
if conn.wgProxyRelay != nil {
|
||||
conn.Log.Debugf("Relay proxy already configured, skipping duplicate setup")
|
||||
// Update status to ensure it's connected
|
||||
conn.statusRelay.SetConnected()
|
||||
return
|
||||
}
|
||||
|
||||
conn.dumpState.RelayConnected()
|
||||
conn.Log.Debugf("Relay connection has been established, setup the WireGuard")
|
||||
|
||||
@@ -472,19 +480,42 @@ func (conn *Conn) onRelayConnectionIsReady(rci RelayConnInfo) {
|
||||
if conn.isICEActive() {
|
||||
conn.Log.Debugf("do not switch to relay because current priority is: %s", conn.currentConnPriority.String())
|
||||
conn.setRelayedProxy(wgProxy)
|
||||
// For WASM, we still need to start the proxy and configure WireGuard
|
||||
// because ICE doesn't actually work in browsers and we rely on relay
|
||||
conn.Log.Infof("WASM check: runtime.GOOS=%s, should start proxy=%v", runtime.GOOS, runtime.GOOS == "js")
|
||||
if runtime.GOOS == "js" {
|
||||
conn.Log.Infof("WASM: starting relay proxy and configuring WireGuard despite ICE being 'active'")
|
||||
wgProxy.Work()
|
||||
|
||||
// Configure WireGuard to use the relay proxy endpoint
|
||||
endpointAddr := wgProxy.EndpointAddr()
|
||||
conn.Log.Infof("WASM: Configuring WireGuard endpoint to proxy address: %v", endpointAddr)
|
||||
if err := conn.configureWGEndpoint(endpointAddr, rci.rosenpassPubKey); err != nil {
|
||||
conn.Log.Errorf("WASM: Failed to update WireGuard peer configuration: %v", err)
|
||||
} else {
|
||||
conn.Log.Infof("WASM: Successfully configured WireGuard endpoint to use proxy at %v", endpointAddr)
|
||||
}
|
||||
|
||||
// Update connection priority to relay for WASM
|
||||
conn.currentConnPriority = conntype.Relay
|
||||
conn.rosenpassRemoteKey = rci.rosenpassPubKey
|
||||
}
|
||||
conn.statusRelay.SetConnected()
|
||||
conn.updateRelayStatus(rci.relayedConn.RemoteAddr().String(), rci.rosenpassPubKey)
|
||||
return
|
||||
}
|
||||
|
||||
wgProxy.Work()
|
||||
if err := conn.configureWGEndpoint(wgProxy.EndpointAddr(), rci.rosenpassPubKey); err != nil {
|
||||
endpointAddr := wgProxy.EndpointAddr()
|
||||
conn.Log.Infof("Configuring WireGuard endpoint to proxy address: %v", endpointAddr)
|
||||
if err := conn.configureWGEndpoint(endpointAddr, rci.rosenpassPubKey); err != nil {
|
||||
if err := wgProxy.CloseConn(); err != nil {
|
||||
conn.Log.Warnf("Failed to close relay connection: %v", err)
|
||||
}
|
||||
conn.Log.Errorf("Failed to update WireGuard peer configuration: %v", err)
|
||||
return
|
||||
}
|
||||
conn.Log.Infof("Successfully configured WireGuard endpoint to use proxy at %v", endpointAddr)
|
||||
|
||||
conn.wgWatcherWg.Add(1)
|
||||
go func() {
|
||||
@@ -663,6 +694,21 @@ func (conn *Conn) isConnectedOnAllWay() (connected bool) {
|
||||
}
|
||||
}()
|
||||
|
||||
// In WASM with forced relay, ICE is not used, so skip ICE check
|
||||
if runtime.GOOS == "js" && os.Getenv("NB_FORCE_RELAY") == "true" {
|
||||
// Only check relay connection status
|
||||
if conn.workerRelay.IsRelayConnectionSupportedWithPeer() {
|
||||
relayConnected := conn.statusRelay.Get() != worker.StatusDisconnected
|
||||
if !relayConnected {
|
||||
conn.Log.Tracef("WASM: relay not connected for connectivity check")
|
||||
}
|
||||
return relayConnected
|
||||
}
|
||||
// If relay is not supported, consider it connected to avoid reconnect loop
|
||||
conn.Log.Tracef("WASM: relay not supported, returning true to avoid reconnect")
|
||||
return true
|
||||
}
|
||||
|
||||
if conn.statusICE.Get() == worker.StatusDisconnected && !conn.workerICE.InProgress() {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package peer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -55,6 +54,22 @@ func (w *WorkerRelay) OnNewOffer(remoteOfferAnswer *OfferAnswer) {
|
||||
}
|
||||
w.relaySupportedOnRemotePeer.Store(true)
|
||||
|
||||
// Check if we already have an active relay connection
|
||||
w.relayLock.Lock()
|
||||
existingConn := w.relayedConn
|
||||
w.relayLock.Unlock()
|
||||
|
||||
if existingConn != nil {
|
||||
w.log.Debugf("relay connection already exists for peer %s, reusing it", w.config.Key)
|
||||
// Connection exists, just ensure proxy is set up if needed
|
||||
go w.conn.onRelayConnectionIsReady(RelayConnInfo{
|
||||
relayedConn: existingConn,
|
||||
rosenpassPubKey: remoteOfferAnswer.RosenpassPubKey,
|
||||
rosenpassAddr: remoteOfferAnswer.RosenpassAddr,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// the relayManager will return with error in case if the connection has lost with relay server
|
||||
currentRelayAddress, err := w.relayManager.RelayInstanceAddress()
|
||||
if err != nil {
|
||||
@@ -66,15 +81,24 @@ func (w *WorkerRelay) OnNewOffer(remoteOfferAnswer *OfferAnswer) {
|
||||
|
||||
relayedConn, err := w.relayManager.OpenConn(w.peerCtx, srv, w.config.Key)
|
||||
if err != nil {
|
||||
if errors.Is(err, relayClient.ErrConnAlreadyExists) {
|
||||
w.log.Debugf("handled offer by reusing existing relay connection")
|
||||
return
|
||||
}
|
||||
// The relay manager never actually returns ErrConnAlreadyExists - it returns
|
||||
// the existing connection with nil error. This error handling is for other failures.
|
||||
w.log.Errorf("failed to open connection via Relay: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
w.relayLock.Lock()
|
||||
// Check if we already stored this connection (might happen if OpenConn returned existing)
|
||||
if w.relayedConn != nil && w.relayedConn == relayedConn {
|
||||
w.relayLock.Unlock()
|
||||
w.log.Debugf("OpenConn returned the same connection we already have for peer %s", w.config.Key)
|
||||
go w.conn.onRelayConnectionIsReady(RelayConnInfo{
|
||||
relayedConn: relayedConn,
|
||||
rosenpassPubKey: remoteOfferAnswer.RosenpassPubKey,
|
||||
rosenpassAddr: remoteOfferAnswer.RosenpassAddr,
|
||||
})
|
||||
return
|
||||
}
|
||||
w.relayedConn = relayedConn
|
||||
w.relayLock.Unlock()
|
||||
|
||||
@@ -123,11 +147,16 @@ func (w *WorkerRelay) CloseConn() {
|
||||
if err := w.relayedConn.Close(); err != nil {
|
||||
w.log.Warnf("failed to close relay connection: %v", err)
|
||||
}
|
||||
// Clear the stored connection to allow reopening
|
||||
w.relayedConn = nil
|
||||
}
|
||||
|
||||
func (w *WorkerRelay) onWGDisconnected() {
|
||||
w.relayLock.Lock()
|
||||
_ = w.relayedConn.Close()
|
||||
if w.relayedConn != nil {
|
||||
_ = w.relayedConn.Close()
|
||||
w.relayedConn = nil
|
||||
}
|
||||
w.relayLock.Unlock()
|
||||
|
||||
w.conn.onRelayDisconnected()
|
||||
@@ -148,6 +177,11 @@ func (w *WorkerRelay) preferredRelayServer(myRelayAddress, remoteRelayAddress st
|
||||
}
|
||||
|
||||
func (w *WorkerRelay) onRelayClientDisconnected() {
|
||||
// Clear the stored connection when relay disconnects
|
||||
w.relayLock.Lock()
|
||||
w.relayedConn = nil
|
||||
w.relayLock.Unlock()
|
||||
|
||||
w.wgWatcher.DisableWgWatcher()
|
||||
go w.conn.onRelayDisconnected()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package systemops
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/statemanager"
|
||||
)
|
||||
|
||||
var ErrRouteNotSupported = errors.New("route operations not supported on js")
|
||||
|
||||
func (r *SysOps) addToRouteTable(prefix netip.Prefix, nexthop Nexthop) error {
|
||||
return ErrRouteNotSupported
|
||||
}
|
||||
|
||||
func (r *SysOps) removeFromRouteTable(prefix netip.Prefix, nexthop Nexthop) error {
|
||||
return ErrRouteNotSupported
|
||||
}
|
||||
|
||||
func GetRoutesFromTable() ([]netip.Prefix, error) {
|
||||
return []netip.Prefix{}, nil
|
||||
}
|
||||
|
||||
func hasSeparateRouting() ([]netip.Prefix, error) {
|
||||
return []netip.Prefix{}, nil
|
||||
}
|
||||
|
||||
// GetDetailedRoutesFromTable returns empty routes for WASM.
|
||||
func GetDetailedRoutesFromTable() ([]DetailedRoute, error) {
|
||||
return []DetailedRoute{}, nil
|
||||
}
|
||||
|
||||
func (r *SysOps) AddVPNRoute(prefix netip.Prefix, intf *net.Interface) error {
|
||||
return ErrRouteNotSupported
|
||||
}
|
||||
|
||||
func (r *SysOps) RemoveVPNRoute(prefix netip.Prefix, intf *net.Interface) error {
|
||||
return ErrRouteNotSupported
|
||||
}
|
||||
|
||||
func (r *SysOps) SetupRouting(initAddresses []net.IP, stateManager *statemanager.Manager) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SysOps) CleanupRouting(stateManager *statemanager.Manager) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !linux && !ios
|
||||
//go:build !linux && !ios && !js
|
||||
|
||||
package systemops
|
||||
|
||||
|
||||
Reference in New Issue
Block a user