mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-02 07:06:41 +00:00
Separate proxy from wg peer config
This commit is contained in:
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/pion/ice/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/proxy"
|
||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||
"github.com/netbirdio/netbird/iface"
|
||||
signal "github.com/netbirdio/netbird/signal/client"
|
||||
@@ -37,7 +36,7 @@ type ConnConfig struct {
|
||||
|
||||
Timeout time.Duration
|
||||
|
||||
ProxyConfig proxy.Config
|
||||
WgConfig WgConfig
|
||||
|
||||
UDPMux ice.UDPMux
|
||||
UDPMuxSrflx ice.UniversalUDPMux
|
||||
@@ -92,7 +91,8 @@ type Conn struct {
|
||||
|
||||
statusRecorder *Status
|
||||
|
||||
proxy proxy.Proxy
|
||||
proxy proxy
|
||||
wgPeerMgr *wgPeerManager
|
||||
remoteModeCh chan ModeMessage
|
||||
meta meta
|
||||
|
||||
@@ -111,14 +111,14 @@ type ModeMessage struct {
|
||||
Direct bool
|
||||
}
|
||||
|
||||
// GetConf returns the connection config
|
||||
func (conn *Conn) GetConf() ConnConfig {
|
||||
return conn.config
|
||||
// WgConfig returns the WireGuard config
|
||||
func (conn *Conn) WgConfig() WgConfig {
|
||||
return conn.config.WgConfig
|
||||
}
|
||||
|
||||
// UpdateConf updates the connection config
|
||||
func (conn *Conn) UpdateConf(conf ConnConfig) {
|
||||
conn.config = conf
|
||||
// UpdateStunTurn update the turn and stun addresses
|
||||
func (conn *Conn) UpdateStunTurn(turnStun []*ice.URL) {
|
||||
conn.config.StunTurn = turnStun
|
||||
}
|
||||
|
||||
// NewConn creates a new not opened Conn to the remote peer.
|
||||
@@ -198,7 +198,7 @@ func (conn *Conn) Open() error {
|
||||
|
||||
peerState := State{PubKey: conn.config.Key}
|
||||
|
||||
peerState.IP = strings.Split(conn.config.ProxyConfig.AllowedIps, "/")[0]
|
||||
peerState.IP = strings.Split(conn.config.WgConfig.AllowedIps, "/")[0]
|
||||
peerState.ConnStatusUpdate = time.Now()
|
||||
peerState.ConnStatus = conn.status
|
||||
|
||||
@@ -290,19 +290,12 @@ func (conn *Conn) Open() error {
|
||||
remoteWgPort = remoteOfferAnswer.WgListenPort
|
||||
}
|
||||
// the ice connection has been established successfully so we are ready to start the proxy
|
||||
err = conn.startProxy(remoteConn, remoteWgPort)
|
||||
err = conn.configureConnection(remoteConn, remoteWgPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if conn.proxy.Type() == proxy.TypeDirectNoProxy {
|
||||
host, _, _ := net.SplitHostPort(remoteConn.LocalAddr().String())
|
||||
rhost, _, _ := net.SplitHostPort(remoteConn.RemoteAddr().String())
|
||||
// direct Wireguard connection
|
||||
log.Infof("directly connected to peer %s [laddr <-> raddr] [%s:%d <-> %s:%d]", conn.config.Key, host, conn.config.LocalWgPort, rhost, remoteWgPort)
|
||||
} else {
|
||||
log.Infof("connected to peer %s [laddr <-> raddr] [%s <-> %s]", conn.config.Key, remoteConn.LocalAddr().String(), remoteConn.RemoteAddr().String())
|
||||
}
|
||||
log.Infof("connected to peer %s with proxy %v, [laddr <-> raddr] [%s <-> %s]", conn.config.Key, conn.proxy != nil, laddr, conn.wgPeerMgr.remoteAddr.String())
|
||||
|
||||
// wait until connection disconnected or has been closed externally (upper layer, e.g. engine)
|
||||
select {
|
||||
@@ -315,7 +308,7 @@ func (conn *Conn) Open() error {
|
||||
}
|
||||
}
|
||||
|
||||
// useProxy determines whether a direct connection (without a go proxy) is possible
|
||||
// isPreferredDirectMode determines whether a direct connection (without a go proxy) is not possible
|
||||
//
|
||||
// There are 3 cases:
|
||||
//
|
||||
@@ -326,35 +319,33 @@ func (conn *Conn) Open() error {
|
||||
// * Local peer uses userspace interface with bind.ICEBind and is not relayed
|
||||
//
|
||||
// Please note, that this check happens when peers were already able to ping each other using ICE layer.
|
||||
func shouldUseProxy(pair *ice.CandidatePair, userspaceBind bool) bool {
|
||||
|
||||
func isPreferredDirectMode(pair *ice.CandidatePair, userspaceBind bool) bool {
|
||||
if !isRelayCandidate(pair.Local) && userspaceBind {
|
||||
log.Debugf("shouldn't use proxy because using Bind and the connection is not relayed")
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
if !isHardNATCandidate(pair.Local) && isHostCandidateWithPublicIP(pair.Remote) {
|
||||
log.Debugf("shouldn't use proxy because the local peer is not behind a hard NAT and the remote one has a public IP")
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
if !isHardNATCandidate(pair.Remote) && isHostCandidateWithPublicIP(pair.Local) {
|
||||
log.Debugf("shouldn't use proxy because the remote peer is not behind a hard NAT and the local one has a public IP")
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
if isHostCandidateWithPrivateIP(pair.Local) && isHostCandidateWithPrivateIP(pair.Remote) && isSameNetworkPrefix(pair) {
|
||||
log.Debugf("shouldn't use proxy because peers are in the same private /16 network")
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
if (isPeerReflexiveCandidateWithPrivateIP(pair.Local) && isHostCandidateWithPrivateIP(pair.Remote) ||
|
||||
isHostCandidateWithPrivateIP(pair.Local) && isPeerReflexiveCandidateWithPrivateIP(pair.Remote)) && isSameNetworkPrefix(pair) {
|
||||
log.Debugf("shouldn't use proxy because peers are in the same private /16 network and one peer is peer reflexive")
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func isSameNetworkPrefix(pair *ice.CandidatePair) bool {
|
||||
@@ -397,27 +388,38 @@ func isPublicIP(address string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// startProxy starts proxying traffic from/to local Wireguard and sets connection status to StatusConnected
|
||||
func (conn *Conn) startProxy(remoteConn net.Conn, remoteWgPort int) error {
|
||||
// configureConnection starts proxying traffic from/to local Wireguard and sets connection status to StatusConnected
|
||||
func (conn *Conn) configureConnection(remoteConn net.Conn, remoteWgPort int) error {
|
||||
conn.mu.Lock()
|
||||
defer conn.mu.Unlock()
|
||||
|
||||
var pair *ice.CandidatePair
|
||||
pair, err := conn.agent.GetSelectedCandidatePair()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
peerState := State{PubKey: conn.config.Key}
|
||||
p := conn.getProxyWithMessageExchange(pair, remoteWgPort)
|
||||
conn.proxy = p
|
||||
err = p.Start(remoteConn)
|
||||
localDirectMode, remoteDirectMode := conn.getNetworkConditions(pair)
|
||||
|
||||
wgPeerMgr := newWgPeerManager(conn.config.WgConfig)
|
||||
err = wgPeerMgr.configureWgPeer(localDirectMode, remoteDirectMode, conn.config.UserspaceBind, remoteConn, remoteWgPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn.wgPeerMgr = wgPeerMgr
|
||||
|
||||
if conn.isProxyNeeded(localDirectMode, remoteDirectMode) {
|
||||
p := NewWireGuardProxy(conn.config.WgConfig.WgListenAddr, conn.config.WgConfig.RemoteKey)
|
||||
err = p.Start(remoteConn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn.proxy = p
|
||||
}
|
||||
|
||||
conn.status = StatusConnected
|
||||
|
||||
// update Peer's state
|
||||
peerState := State{PubKey: conn.config.Key}
|
||||
peerState.ConnStatus = conn.status
|
||||
peerState.ConnStatusUpdate = time.Now()
|
||||
peerState.LocalIceCandidateType = pair.Local.Type().String()
|
||||
@@ -425,7 +427,7 @@ func (conn *Conn) startProxy(remoteConn net.Conn, remoteWgPort int) error {
|
||||
if pair.Local.Type() == ice.CandidateTypeRelay || pair.Remote.Type() == ice.CandidateTypeRelay {
|
||||
peerState.Relayed = true
|
||||
}
|
||||
peerState.Direct = p.Type() == proxy.TypeDirectNoProxy || p.Type() == proxy.TypeNoProxy
|
||||
peerState.Direct = conn.proxy == nil
|
||||
|
||||
err = conn.statusRecorder.UpdatePeerState(peerState)
|
||||
if err != nil {
|
||||
@@ -435,27 +437,29 @@ func (conn *Conn) startProxy(remoteConn net.Conn, remoteWgPort int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (conn *Conn) getProxyWithMessageExchange(pair *ice.CandidatePair, remoteWgPort int) proxy.Proxy {
|
||||
useProxy := shouldUseProxy(pair, conn.config.UserspaceBind)
|
||||
localDirectMode := !useProxy
|
||||
remoteDirectMode := localDirectMode
|
||||
func (conn *Conn) getNetworkConditions(pair *ice.CandidatePair) (bool, bool) {
|
||||
var localDirectMode, remoteDirectMode bool
|
||||
localDirectMode = isPreferredDirectMode(pair, conn.config.UserspaceBind)
|
||||
|
||||
if conn.meta.protoSupport.DirectCheck {
|
||||
go conn.sendLocalDirectMode(localDirectMode)
|
||||
// will block until message received or timeout
|
||||
remoteDirectMode = conn.receiveRemoteDirectMode()
|
||||
} else {
|
||||
remoteDirectMode = localDirectMode
|
||||
}
|
||||
return localDirectMode, remoteDirectMode
|
||||
}
|
||||
|
||||
func (conn *Conn) isProxyNeeded(localDirectMode, remoteDirectMode bool) bool {
|
||||
if conn.config.UserspaceBind && localDirectMode {
|
||||
return proxy.NewNoProxy(conn.config.ProxyConfig)
|
||||
return false
|
||||
}
|
||||
|
||||
if localDirectMode && remoteDirectMode {
|
||||
return proxy.NewDirectNoProxy(conn.config.ProxyConfig, remoteWgPort)
|
||||
return false
|
||||
}
|
||||
|
||||
log.Debugf("falling back to local proxy mode with peer %s", conn.config.Key)
|
||||
return proxy.NewWireGuardProxy(conn.config.ProxyConfig)
|
||||
return true
|
||||
}
|
||||
|
||||
func (conn *Conn) sendLocalDirectMode(localMode bool) {
|
||||
@@ -500,20 +504,26 @@ func (conn *Conn) cleanup() error {
|
||||
conn.mu.Lock()
|
||||
defer conn.mu.Unlock()
|
||||
|
||||
var err1, err2, err3 error
|
||||
if conn.agent != nil {
|
||||
err := conn.agent.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
err1 = conn.agent.Close()
|
||||
if err1 == nil {
|
||||
conn.agent = nil
|
||||
}
|
||||
}
|
||||
|
||||
if conn.wgPeerMgr != nil {
|
||||
err2 = conn.wgPeerMgr.close()
|
||||
if err2 == nil {
|
||||
conn.wgPeerMgr = nil
|
||||
}
|
||||
conn.agent = nil
|
||||
}
|
||||
|
||||
if conn.proxy != nil {
|
||||
err := conn.proxy.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
err3 = conn.proxy.Close()
|
||||
if err3 == nil {
|
||||
conn.proxy = nil
|
||||
}
|
||||
conn.proxy = nil
|
||||
}
|
||||
|
||||
if conn.notifyDisconnected != nil {
|
||||
@@ -535,8 +545,13 @@ func (conn *Conn) cleanup() error {
|
||||
}
|
||||
|
||||
log.Debugf("cleaned up connection to peer %s", conn.config.Key)
|
||||
|
||||
return nil
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
return err3
|
||||
}
|
||||
|
||||
// SetSignalOffer sets a handler function to be triggered by Conn when a new connection offer has to be signalled to the remote peer
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/pion/ice/v2"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/proxy"
|
||||
"github.com/netbirdio/netbird/iface"
|
||||
sproto "github.com/netbirdio/netbird/signal/proto"
|
||||
)
|
||||
@@ -22,7 +21,7 @@ var connConf = ConnConfig{
|
||||
StunTurn: []*ice.URL{},
|
||||
InterfaceBlackList: nil,
|
||||
Timeout: time.Second,
|
||||
ProxyConfig: proxy.Config{},
|
||||
WgConfig: WgConfig{},
|
||||
LocalWgPort: 51820,
|
||||
}
|
||||
|
||||
@@ -244,87 +243,87 @@ func TestConn_ShouldUseProxy(t *testing.T) {
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "Use Proxy When Local Candidate Is Relay",
|
||||
name: "Use proxy When Local Candidate Is Relay",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: relayCandidate,
|
||||
Remote: privateHostCandidate,
|
||||
},
|
||||
expected: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Use Proxy When Remote Candidate Is Relay",
|
||||
name: "Use proxy When Remote Candidate Is Relay",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: privateHostCandidate,
|
||||
Remote: relayCandidate,
|
||||
},
|
||||
expected: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Use Proxy When Local Candidate Is Peer Reflexive",
|
||||
name: "Use proxy When Local Candidate Is Peer Reflexive",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: prflxCandidate,
|
||||
Remote: privateHostCandidate,
|
||||
},
|
||||
expected: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Use Proxy When Remote Candidate Is Peer Reflexive",
|
||||
name: "Use proxy When Remote Candidate Is Peer Reflexive",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: privateHostCandidate,
|
||||
Remote: prflxCandidate,
|
||||
},
|
||||
expected: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Don't Use Proxy When Local Candidate Is Public And Remote Is Private",
|
||||
name: "Don't Use proxy When Local Candidate Is Public And Remote Is Private",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: publicHostCandidate,
|
||||
Remote: privateHostCandidate,
|
||||
},
|
||||
expected: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Don't Use Proxy When Remote Candidate Is Public And Local Is Private",
|
||||
name: "Don't Use proxy When Remote Candidate Is Public And Local Is Private",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: privateHostCandidate,
|
||||
Remote: publicHostCandidate,
|
||||
},
|
||||
expected: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Don't Use Proxy When Local Candidate is Public And Remote Is Server Reflexive",
|
||||
name: "Don't Use proxy When Local Candidate is Public And Remote Is Server Reflexive",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: publicHostCandidate,
|
||||
Remote: srflxCandidate,
|
||||
},
|
||||
expected: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Don't Use Proxy When Remote Candidate is Public And Local Is Server Reflexive",
|
||||
name: "Don't Use proxy When Remote Candidate is Public And Local Is Server Reflexive",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: srflxCandidate,
|
||||
Remote: publicHostCandidate,
|
||||
},
|
||||
expected: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Don't Use Proxy When Both Candidates Are Public",
|
||||
name: "Don't Use proxy When Both Candidates Are Public",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: publicHostCandidate,
|
||||
Remote: publicHostCandidate,
|
||||
},
|
||||
expected: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Don't Use Proxy When Both Candidates Are Private",
|
||||
name: "Don't Use proxy When Both Candidates Are Private",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: privateHostCandidate,
|
||||
Remote: privateHostCandidate,
|
||||
},
|
||||
expected: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Don't Use Proxy When Both Candidates are in private network and one is peer reflexive",
|
||||
name: "Don't Use proxy When Both Candidates are in private network and one is peer reflexive",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: &mockICECandidate{AddressFunc: func() string {
|
||||
return "10.16.102.168"
|
||||
@@ -339,10 +338,10 @@ func TestConn_ShouldUseProxy(t *testing.T) {
|
||||
return ice.CandidateTypePeerReflexive
|
||||
}},
|
||||
},
|
||||
expected: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Should Use Proxy When Both Candidates are in private network and both are peer reflexive",
|
||||
name: "Should Use proxy When Both Candidates are in private network and both are peer reflexive",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: &mockICECandidate{AddressFunc: func() string {
|
||||
return "10.16.102.168"
|
||||
@@ -357,13 +356,13 @@ func TestConn_ShouldUseProxy(t *testing.T) {
|
||||
return ice.CandidateTypePeerReflexive
|
||||
}},
|
||||
},
|
||||
expected: true,
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
result := shouldUseProxy(testCase.candatePair, false)
|
||||
result := isPreferredDirectMode(testCase.candatePair, false)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("got a different result. Expected %t Got %t", testCase.expected, result)
|
||||
}
|
||||
@@ -394,57 +393,57 @@ func TestGetProxyWithMessageExchange(t *testing.T) {
|
||||
candatePair *ice.CandidatePair
|
||||
inputDirectModeSupport bool
|
||||
inputRemoteModeMessage bool
|
||||
expected proxy.Type
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "Should Result In Using Wireguard Proxy When Local Eval Is Use Proxy",
|
||||
name: "Should Result In Using Wireguard proxy When Local Eval Is Use proxy",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: relayCandidate,
|
||||
Remote: publicHostCandidate,
|
||||
},
|
||||
inputDirectModeSupport: true,
|
||||
inputRemoteModeMessage: true,
|
||||
expected: proxy.TypeWireGuard,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Should Result In Using Wireguard Proxy When Remote Eval Is Use Proxy",
|
||||
name: "Should Result In Using Wireguard proxy When Remote Eval Is Use proxy",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: publicHostCandidate,
|
||||
Remote: publicHostCandidate,
|
||||
},
|
||||
inputDirectModeSupport: true,
|
||||
inputRemoteModeMessage: false,
|
||||
expected: proxy.TypeWireGuard,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Should Result In Using Wireguard Proxy When Remote Direct Mode Support Is False And Local Eval Is Use Proxy",
|
||||
name: "Should Result In Using Wireguard proxy When Remote Direct Mode Support Is False And Local Eval Is Use proxy",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: relayCandidate,
|
||||
Remote: publicHostCandidate,
|
||||
},
|
||||
inputDirectModeSupport: false,
|
||||
inputRemoteModeMessage: false,
|
||||
expected: proxy.TypeWireGuard,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Should Result In Using Direct When Remote Direct Mode Support Is False And Local Eval Is No Use Proxy",
|
||||
name: "Should Result In Using Direct When Remote Direct Mode Support Is False And Local Eval Is No Use proxy",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: publicHostCandidate,
|
||||
Remote: publicHostCandidate,
|
||||
},
|
||||
inputDirectModeSupport: false,
|
||||
inputRemoteModeMessage: false,
|
||||
expected: proxy.TypeDirectNoProxy,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Should Result In Using Direct When Local And Remote Eval Is No Proxy",
|
||||
name: "Should Result In Using Direct When Local And Remote Eval Is No proxy",
|
||||
candatePair: &ice.CandidatePair{
|
||||
Local: publicHostCandidate,
|
||||
Remote: publicHostCandidate,
|
||||
},
|
||||
inputDirectModeSupport: true,
|
||||
inputRemoteModeMessage: true,
|
||||
expected: proxy.TypeDirectNoProxy,
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
@@ -464,15 +463,15 @@ func TestGetProxyWithMessageExchange(t *testing.T) {
|
||||
Direct: testCase.inputRemoteModeMessage,
|
||||
})
|
||||
})
|
||||
|
||||
resultProxy := conn.getProxyWithMessageExchange(testCase.candatePair, 1000)
|
||||
conn.config.UserspaceBind = false
|
||||
resultProxy := conn.isProxyNeeded(testCase.inputDirectModeSupport, testCase.inputRemoteModeMessage)
|
||||
|
||||
err = g.Wait()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if resultProxy.Type() != testCase.expected {
|
||||
t.Errorf("result didn't match expected value: Expected: %s, Got: %s", testCase.expected, resultProxy.Type())
|
||||
if resultProxy != testCase.expected {
|
||||
t.Errorf("result didn't match expected value: Expected: %v, Got: %v", testCase.expected, resultProxy)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
12
client/internal/peer/proxy.go
Normal file
12
client/internal/peer/proxy.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
type proxy interface {
|
||||
io.Closer
|
||||
// Start creates a local remoteConn and starts proxying data from/to remoteConn
|
||||
Start(remoteConn net.Conn) error
|
||||
}
|
||||
104
client/internal/peer/proxy_wg.go
Normal file
104
client/internal/peer/proxy_wg.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// WireGuardProxy proxies
|
||||
type WireGuardProxy struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
wgListenAddr string
|
||||
remoteKey string
|
||||
|
||||
remoteConn net.Conn
|
||||
localConn net.Conn
|
||||
}
|
||||
|
||||
func NewWireGuardProxy(wgListenAddr, remoteKey string) *WireGuardProxy {
|
||||
p := &WireGuardProxy{
|
||||
wgListenAddr: wgListenAddr,
|
||||
remoteKey: remoteKey,
|
||||
}
|
||||
p.ctx, p.cancel = context.WithCancel(context.Background())
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *WireGuardProxy) Start(remoteConn net.Conn) error {
|
||||
p.remoteConn = remoteConn
|
||||
|
||||
var err error
|
||||
p.localConn, err = net.Dial("udp", p.wgListenAddr)
|
||||
if err != nil {
|
||||
log.Errorf("failed dialing to local Wireguard port %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
go p.proxyToRemote()
|
||||
go p.proxyToLocal()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *WireGuardProxy) Close() error {
|
||||
p.cancel()
|
||||
if c := p.localConn; c != nil {
|
||||
err := p.localConn.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// proxyToRemote proxies everything from Wireguard to the RemoteKey peer
|
||||
// blocks
|
||||
func (p *WireGuardProxy) proxyToRemote() {
|
||||
|
||||
buf := make([]byte, 1500)
|
||||
for {
|
||||
select {
|
||||
case <-p.ctx.Done():
|
||||
log.Debugf("stopped proxying to remote peer %s due to closed connection", p.remoteKey)
|
||||
return
|
||||
default:
|
||||
n, err := p.localConn.Read(buf)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = p.remoteConn.Write(buf[:n])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// proxyToLocal proxies everything from the RemoteKey peer to local Wireguard
|
||||
// blocks
|
||||
func (p *WireGuardProxy) proxyToLocal() {
|
||||
|
||||
buf := make([]byte, 1500)
|
||||
for {
|
||||
select {
|
||||
case <-p.ctx.Done():
|
||||
log.Debugf("stopped proxying from remote peer %s due to closed connection", p.remoteKey)
|
||||
return
|
||||
default:
|
||||
n, err := p.remoteConn.Read(buf)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = p.localConn.Write(buf[:n])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
client/internal/peer/wg_peer_manager.go
Normal file
68
client/internal/peer/wg_peer_manager.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
"github.com/netbirdio/netbird/iface"
|
||||
)
|
||||
|
||||
const defaultWgKeepAlive = 25 * time.Second
|
||||
|
||||
type WgConfig struct {
|
||||
WgListenAddr string
|
||||
RemoteKey string
|
||||
WgInterface *iface.WGIface
|
||||
AllowedIps string
|
||||
PreSharedKey *wgtypes.Key
|
||||
}
|
||||
|
||||
type wgPeerManager struct {
|
||||
wgConfig WgConfig
|
||||
|
||||
remoteAddr *net.UDPAddr
|
||||
}
|
||||
|
||||
func newWgPeerManager(wgConfig WgConfig) *wgPeerManager {
|
||||
return &wgPeerManager{
|
||||
wgConfig: wgConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func (mgr *wgPeerManager) configureWgPeer(localDirectMode, remoteDirectMode, userspaceBind bool, remoteConn net.Conn, remoteWgPort int) error {
|
||||
var err error
|
||||
mgr.remoteAddr, err = net.ResolveUDPAddr("udp", remoteConn.RemoteAddr().String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if remoteDirectMode {
|
||||
mgr.remoteAddr.Port = remoteWgPort
|
||||
}
|
||||
|
||||
if userspaceBind && localDirectMode {
|
||||
return mgr.updateWgPeer()
|
||||
}
|
||||
|
||||
if localDirectMode && remoteDirectMode {
|
||||
return mgr.updateWgPeer()
|
||||
}
|
||||
|
||||
mgr.remoteAddr, err = net.ResolveUDPAddr("udp", mgr.wgConfig.WgListenAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return mgr.updateWgPeer()
|
||||
}
|
||||
|
||||
// Close removes peer from the WireGuard interface
|
||||
func (mgr *wgPeerManager) close() error {
|
||||
return mgr.wgConfig.WgInterface.RemovePeer(mgr.wgConfig.RemoteKey)
|
||||
}
|
||||
|
||||
func (mgr *wgPeerManager) updateWgPeer() error {
|
||||
return mgr.wgConfig.WgInterface.UpdatePeer(mgr.wgConfig.RemoteKey, mgr.wgConfig.AllowedIps, defaultWgKeepAlive,
|
||||
mgr.remoteAddr, mgr.wgConfig.PreSharedKey)
|
||||
}
|
||||
Reference in New Issue
Block a user