mirror of
https://github.com/netbirdio/netbird.git
synced 2025-07-22 16:44:26 +02:00
- When a peer is connected with TURN and a Relay connection is established, do not force switching to Relay. Keep using TURN until disconnection. -In the proxy preparation phase, the Bind Proxy does not set the remote conn as a fake address for Bind. When running the Work() function, the proper proxy instance updates the conn inside the Bind.
160 lines
3.2 KiB
Go
160 lines
3.2 KiB
Go
package bind
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/netip"
|
|
"strings"
|
|
"sync"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/netbirdio/netbird/client/iface/bind"
|
|
)
|
|
|
|
type ProxyBind struct {
|
|
Bind *bind.ICEBind
|
|
|
|
fakeNetIP *netip.AddrPort
|
|
wgBindEndpoint *bind.Endpoint
|
|
remoteConn net.Conn
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
closeMu sync.Mutex
|
|
closed bool
|
|
|
|
pausedMu sync.Mutex
|
|
paused bool
|
|
isStarted bool
|
|
}
|
|
|
|
// AddTurnConn adds a new connection to the bind.
|
|
// endpoint is the NetBird address of the remote peer. The SetEndpoint return with the address what will be used in the
|
|
// WireGuard configuration.
|
|
func (p *ProxyBind) AddTurnConn(ctx context.Context, nbAddr *net.UDPAddr, remoteConn net.Conn) error {
|
|
fakeNetIP, err := fakeAddress(nbAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.fakeNetIP = fakeNetIP
|
|
p.wgBindEndpoint = &bind.Endpoint{AddrPort: *fakeNetIP}
|
|
p.remoteConn = remoteConn
|
|
p.ctx, p.cancel = context.WithCancel(ctx)
|
|
return nil
|
|
|
|
}
|
|
func (p *ProxyBind) EndpointAddr() *net.UDPAddr {
|
|
return &net.UDPAddr{
|
|
IP: p.fakeNetIP.Addr().AsSlice(),
|
|
Port: int(p.fakeNetIP.Port()),
|
|
Zone: p.fakeNetIP.Addr().Zone(),
|
|
}
|
|
}
|
|
|
|
func (p *ProxyBind) Work() {
|
|
if p.remoteConn == nil {
|
|
return
|
|
}
|
|
|
|
p.Bind.SetEndpoint(p.fakeNetIP.Addr(), p.remoteConn)
|
|
|
|
p.pausedMu.Lock()
|
|
p.paused = false
|
|
p.pausedMu.Unlock()
|
|
|
|
// Start the proxy only once
|
|
if !p.isStarted {
|
|
p.isStarted = true
|
|
go p.proxyToLocal(p.ctx)
|
|
}
|
|
}
|
|
|
|
func (p *ProxyBind) Pause() {
|
|
if p.remoteConn == nil {
|
|
return
|
|
}
|
|
|
|
p.pausedMu.Lock()
|
|
p.paused = true
|
|
p.pausedMu.Unlock()
|
|
}
|
|
|
|
func (p *ProxyBind) CloseConn() error {
|
|
if p.cancel == nil {
|
|
return fmt.Errorf("proxy not started")
|
|
}
|
|
return p.close()
|
|
}
|
|
|
|
func (p *ProxyBind) close() error {
|
|
p.closeMu.Lock()
|
|
defer p.closeMu.Unlock()
|
|
|
|
if p.closed {
|
|
return nil
|
|
}
|
|
p.closed = true
|
|
|
|
p.cancel()
|
|
|
|
p.Bind.RemoveEndpoint(p.fakeNetIP.Addr())
|
|
|
|
if rErr := p.remoteConn.Close(); rErr != nil && !errors.Is(rErr, net.ErrClosed) {
|
|
return rErr
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *ProxyBind) proxyToLocal(ctx context.Context) {
|
|
defer func() {
|
|
if err := p.close(); err != nil {
|
|
log.Warnf("failed to close remote conn: %s", err)
|
|
}
|
|
}()
|
|
|
|
for {
|
|
buf := make([]byte, 1500)
|
|
n, err := p.remoteConn.Read(buf)
|
|
if err != nil {
|
|
if ctx.Err() != nil {
|
|
return
|
|
}
|
|
log.Errorf("failed to read from remote conn: %s, %s", p.remoteConn.RemoteAddr(), err)
|
|
return
|
|
}
|
|
|
|
p.pausedMu.Lock()
|
|
if p.paused {
|
|
p.pausedMu.Unlock()
|
|
continue
|
|
}
|
|
|
|
msg := bind.RecvMessage{
|
|
Endpoint: p.wgBindEndpoint,
|
|
Buffer: buf[:n],
|
|
}
|
|
p.Bind.RecvChan <- msg
|
|
p.pausedMu.Unlock()
|
|
}
|
|
}
|
|
|
|
// fakeAddress returns a fake address that is used to as an identifier for the peer.
|
|
// The fake address is in the format of 127.1.x.x where x.x is the last two octets of the peer address.
|
|
func fakeAddress(peerAddress *net.UDPAddr) (*netip.AddrPort, error) {
|
|
octets := strings.Split(peerAddress.IP.String(), ".")
|
|
if len(octets) != 4 {
|
|
return nil, fmt.Errorf("invalid IP format")
|
|
}
|
|
|
|
fakeIP, err := netip.ParseAddr(fmt.Sprintf("127.1.%s.%s", octets[2], octets[3]))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse new IP: %w", err)
|
|
}
|
|
|
|
netipAddr := netip.AddrPortFrom(fakeIP, uint16(peerAddress.Port))
|
|
return &netipAddr, nil
|
|
}
|