mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 00:06:38 +00:00
[client,signal,management] Add browser client support (#4415)
This commit is contained in:
7
client/iface/bind/error.go
Normal file
7
client/iface/bind/error.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package bind
|
||||
|
||||
import "fmt"
|
||||
|
||||
var (
|
||||
ErrUDPMUXNotSupported = fmt.Errorf("UDPMUX is not supported in WASM")
|
||||
)
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !js
|
||||
|
||||
package bind
|
||||
|
||||
import (
|
||||
@@ -21,11 +23,6 @@ import (
|
||||
nbnet "github.com/netbirdio/netbird/client/net"
|
||||
)
|
||||
|
||||
type RecvMessage struct {
|
||||
Endpoint *Endpoint
|
||||
Buffer []byte
|
||||
}
|
||||
|
||||
type receiverCreator struct {
|
||||
iceBind *ICEBind
|
||||
}
|
||||
@@ -43,37 +40,38 @@ func (rc receiverCreator) CreateIPv4ReceiverFn(pc *ipv4.PacketConn, conn *net.UD
|
||||
// use the port because in the Send function the wgConn.Endpoint the port info is not exported.
|
||||
type ICEBind struct {
|
||||
*wgConn.StdNetBind
|
||||
recvChan chan RecvMessage
|
||||
|
||||
transportNet transport.Net
|
||||
filterFn udpmux.FilterFn
|
||||
endpoints map[netip.Addr]net.Conn
|
||||
endpointsMu sync.Mutex
|
||||
address wgaddr.Address
|
||||
mtu uint16
|
||||
|
||||
endpoints map[netip.Addr]net.Conn
|
||||
endpointsMu sync.Mutex
|
||||
recvChan chan recvMessage
|
||||
// every time when Close() is called (i.e. BindUpdate()) we need to close exit from the receiveRelayed and create a
|
||||
// new closed channel. With the closedChanMu we can safely close the channel and create a new one
|
||||
closedChan chan struct{}
|
||||
closedChanMu sync.RWMutex // protect the closeChan recreation from reading from it.
|
||||
closed bool
|
||||
|
||||
muUDPMux sync.Mutex
|
||||
udpMux *udpmux.UniversalUDPMuxDefault
|
||||
address wgaddr.Address
|
||||
mtu uint16
|
||||
closedChan chan struct{}
|
||||
closedChanMu sync.RWMutex // protect the closeChan recreation from reading from it.
|
||||
closed bool
|
||||
activityRecorder *ActivityRecorder
|
||||
|
||||
muUDPMux sync.Mutex
|
||||
udpMux *udpmux.UniversalUDPMuxDefault
|
||||
}
|
||||
|
||||
func NewICEBind(transportNet transport.Net, filterFn udpmux.FilterFn, address wgaddr.Address, mtu uint16) *ICEBind {
|
||||
b, _ := wgConn.NewStdNetBind().(*wgConn.StdNetBind)
|
||||
ib := &ICEBind{
|
||||
StdNetBind: b,
|
||||
recvChan: make(chan RecvMessage, 1),
|
||||
transportNet: transportNet,
|
||||
filterFn: filterFn,
|
||||
address: address,
|
||||
mtu: mtu,
|
||||
endpoints: make(map[netip.Addr]net.Conn),
|
||||
recvChan: make(chan recvMessage, 1),
|
||||
closedChan: make(chan struct{}),
|
||||
closed: true,
|
||||
mtu: mtu,
|
||||
address: address,
|
||||
activityRecorder: NewActivityRecorder(),
|
||||
}
|
||||
|
||||
@@ -84,10 +82,6 @@ func NewICEBind(transportNet transport.Net, filterFn udpmux.FilterFn, address wg
|
||||
return ib
|
||||
}
|
||||
|
||||
func (s *ICEBind) MTU() uint16 {
|
||||
return s.mtu
|
||||
}
|
||||
|
||||
func (s *ICEBind) Open(uport uint16) ([]wgConn.ReceiveFunc, uint16, error) {
|
||||
s.closed = false
|
||||
s.closedChanMu.Lock()
|
||||
@@ -140,6 +134,16 @@ func (b *ICEBind) RemoveEndpoint(fakeIP netip.Addr) {
|
||||
delete(b.endpoints, fakeIP)
|
||||
}
|
||||
|
||||
func (b *ICEBind) ReceiveFromEndpoint(ctx context.Context, ep *Endpoint, buf []byte) {
|
||||
select {
|
||||
case <-b.closedChan:
|
||||
return
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case b.recvChan <- recvMessage{ep, buf}:
|
||||
}
|
||||
}
|
||||
|
||||
func (b *ICEBind) Send(bufs [][]byte, ep wgConn.Endpoint) error {
|
||||
b.endpointsMu.Lock()
|
||||
conn, ok := b.endpoints[ep.DstIP()]
|
||||
@@ -156,14 +160,6 @@ func (b *ICEBind) Send(bufs [][]byte, ep wgConn.Endpoint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ICEBind) Recv(ctx context.Context, msg RecvMessage) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case b.recvChan <- msg:
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ICEBind) createIPv4ReceiverFn(pc *ipv4.PacketConn, conn *net.UDPConn, rxOffload bool, msgsPool *sync.Pool) wgConn.ReceiveFunc {
|
||||
s.muUDPMux.Lock()
|
||||
defer s.muUDPMux.Unlock()
|
||||
|
||||
6
client/iface/bind/recv_msg.go
Normal file
6
client/iface/bind/recv_msg.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package bind
|
||||
|
||||
type recvMessage struct {
|
||||
Endpoint *Endpoint
|
||||
Buffer []byte
|
||||
}
|
||||
125
client/iface/bind/relay_bind.go
Normal file
125
client/iface/bind/relay_bind.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package bind
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.zx2c4.com/wireguard/conn"
|
||||
|
||||
"github.com/netbirdio/netbird/client/iface/udpmux"
|
||||
)
|
||||
|
||||
// RelayBindJS is a conn.Bind implementation for WebAssembly environments.
|
||||
// Do not limit to build only js, because we want to be able to run tests
|
||||
type RelayBindJS struct {
|
||||
*conn.StdNetBind
|
||||
|
||||
recvChan chan recvMessage
|
||||
endpoints map[netip.Addr]net.Conn
|
||||
endpointsMu sync.Mutex
|
||||
activityRecorder *ActivityRecorder
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewRelayBindJS() *RelayBindJS {
|
||||
return &RelayBindJS{
|
||||
recvChan: make(chan recvMessage, 100),
|
||||
endpoints: make(map[netip.Addr]net.Conn),
|
||||
activityRecorder: NewActivityRecorder(),
|
||||
}
|
||||
}
|
||||
|
||||
// Open creates a receive function for handling relay packets in WASM.
|
||||
func (s *RelayBindJS) Open(uport uint16) ([]conn.ReceiveFunc, uint16, error) {
|
||||
log.Debugf("Open: creating receive function for port %d", uport)
|
||||
|
||||
s.ctx, s.cancel = context.WithCancel(context.Background())
|
||||
|
||||
receiveFn := func(bufs [][]byte, sizes []int, eps []conn.Endpoint) (int, error) {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return 0, net.ErrClosed
|
||||
case 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
|
||||
}
|
||||
|
||||
func (s *RelayBindJS) Close() error {
|
||||
if s.cancel == nil {
|
||||
return nil
|
||||
}
|
||||
log.Debugf("close RelayBindJS")
|
||||
s.cancel()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *RelayBindJS) ReceiveFromEndpoint(ctx context.Context, ep *Endpoint, buf []byte) {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case s.recvChan <- recvMessage{ep, buf}:
|
||||
}
|
||||
}
|
||||
|
||||
// Send forwards packets through the relay connection for WASM.
|
||||
func (s *RelayBindJS) 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 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *RelayBindJS) SetEndpoint(fakeIP netip.Addr, conn net.Conn) {
|
||||
b.endpointsMu.Lock()
|
||||
b.endpoints[fakeIP] = conn
|
||||
b.endpointsMu.Unlock()
|
||||
}
|
||||
|
||||
func (s *RelayBindJS) RemoveEndpoint(fakeIP netip.Addr) {
|
||||
s.endpointsMu.Lock()
|
||||
defer s.endpointsMu.Unlock()
|
||||
|
||||
delete(s.endpoints, fakeIP)
|
||||
}
|
||||
|
||||
// GetICEMux returns the ICE UDPMux that was created and used by ICEBind
|
||||
func (s *RelayBindJS) GetICEMux() (*udpmux.UniversalUDPMuxDefault, error) {
|
||||
return nil, ErrUDPMUXNotSupported
|
||||
}
|
||||
|
||||
func (s *RelayBindJS) ActivityRecorder() *ActivityRecorder {
|
||||
return s.activityRecorder
|
||||
}
|
||||
Reference in New Issue
Block a user