Files
netbird/client/iface/bind/ice_bind_js.go
2025-08-29 11:11:18 +02:00

142 lines
3.3 KiB
Go

//go:build js
package bind
import (
"net"
"net/netip"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/conn"
)
// GetICEMux returns a dummy UDP mux for WASM since browsers don't support UDP.
func (s *ICEBind) GetICEMux() (*UniversalUDPMuxDefault, error) {
return nil, nil
}
// Open creates a receive function for handling relay packets in WASM.
func (s *ICEBind) Open(uport uint16) ([]conn.ReceiveFunc, uint16, error) {
log.Debugf("Open: creating receive function for port %d", uport)
s.closedMu.Lock()
s.closed = false
s.closedMu.Unlock()
if !s.receiverCreated {
s.receiverCreated = true
log.Debugf("Open: first call, setting receiverCreated=true")
}
receiveFn := func(bufs [][]byte, sizes []int, eps []conn.Endpoint) (int, error) {
s.closedMu.Lock()
if s.closed {
s.closedMu.Unlock()
return 0, net.ErrClosed
}
s.closedMu.Unlock()
msg, ok := <-s.RecvChan
if !ok {
return 0, net.ErrClosed
}
copy(bufs[0], msg.Buffer)
sizes[0] = len(msg.Buffer)
eps[0] = conn.Endpoint(msg.Endpoint)
return 1, nil
}
log.Debugf("Open: receive function created, returning port %d", uport)
return []conn.ReceiveFunc{receiveFn}, uport, nil
}
// SetMark is not applicable in WASM/browser environment.
func (s *ICEBind) SetMark(_ uint32) error {
return nil
}
// Send forwards packets through the relay connection for WASM.
func (s *ICEBind) Send(bufs [][]byte, ep conn.Endpoint) error {
if ep == nil {
return nil
}
fakeIP := ep.DstIP()
s.endpointsMu.Lock()
relayConn, ok := s.endpoints[fakeIP]
s.endpointsMu.Unlock()
if !ok {
return nil
}
for _, buf := range bufs {
if _, err := relayConn.Write(buf); err != nil {
log.Errorf("Send: failed to write to relay: %v", err)
return err
}
}
return nil
}
// SetEndpoint stores a relay endpoint for a fake IP.
func (s *ICEBind) SetEndpoint(fakeIP netip.Addr, conn net.Conn) {
s.endpointsMu.Lock()
defer s.endpointsMu.Unlock()
if oldConn, exists := s.endpoints[fakeIP]; exists {
if oldConn != conn {
log.Debugf("SetEndpoint: replacing existing connection for %s", fakeIP)
if err := oldConn.Close(); err != nil {
log.Debugf("SetEndpoint: error closing old connection: %v", err)
}
s.endpoints[fakeIP] = conn
} else {
log.Tracef("SetEndpoint: same connection already set for %s, skipping", fakeIP)
}
} else {
log.Debugf("SetEndpoint: setting new relay connection for fake IP %s", fakeIP)
s.endpoints[fakeIP] = conn
}
}
// RemoveEndpoint removes a relay endpoint.
func (s *ICEBind) RemoveEndpoint(fakeIP netip.Addr) {
s.endpointsMu.Lock()
defer s.endpointsMu.Unlock()
delete(s.endpoints, fakeIP)
}
// BatchSize returns the batch size for WASM.
func (s *ICEBind) BatchSize() int {
return 1
}
// ParseEndpoint parses an endpoint string.
func (s *ICEBind) ParseEndpoint(s2 string) (conn.Endpoint, error) {
addrPort, err := netip.ParseAddrPort(s2)
if err != nil {
log.Errorf("ParseEndpoint: failed to parse %s: %v", s2, err)
return nil, err
}
ep := &Endpoint{AddrPort: addrPort}
return ep, nil
}
// Close closes the ICEBind.
func (s *ICEBind) Close() error {
log.Debugf("Close: closing ICEBind (receiverCreated=%v)", s.receiverCreated)
s.closedMu.Lock()
s.closed = true
s.closedMu.Unlock()
s.receiverCreated = false
log.Debugf("Close: returning from Close")
return nil
}