mirror of
https://github.com/netbirdio/netbird.git
synced 2025-06-19 00:06:58 +02:00
Support no-proxy mode connection mode (#245)
When one of the peers has a static public host IP or both peers are in the same local network we establish a direct Wireguard connection bypassing proxy usage. This helps reduce FD usage and improves performance.
This commit is contained in:
parent
69cda73bbb
commit
5d4c2643a3
@ -2,6 +2,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/wiretrustee/wiretrustee/iface"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cenkalti/backoff/v4"
|
"github.com/cenkalti/backoff/v4"
|
||||||
@ -71,7 +72,7 @@ func createEngineConfig(key wgtypes.Key, config *internal.Config, peerConfig *mg
|
|||||||
WgAddr: peerConfig.Address,
|
WgAddr: peerConfig.Address,
|
||||||
IFaceBlackList: iFaceBlackList,
|
IFaceBlackList: iFaceBlackList,
|
||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
WgPort: internal.WgPort,
|
WgPort: iface.DefaultWgPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.PreSharedKey != "" {
|
if config.PreSharedKey != "" {
|
||||||
|
@ -31,8 +31,6 @@ const (
|
|||||||
PeerConnectionTimeoutMin = 30000 // ms
|
PeerConnectionTimeoutMin = 30000 // ms
|
||||||
)
|
)
|
||||||
|
|
||||||
const WgPort = 51820
|
|
||||||
|
|
||||||
// EngineConfig is a config for the Engine
|
// EngineConfig is a config for the Engine
|
||||||
type EngineConfig struct {
|
type EngineConfig struct {
|
||||||
WgPort int
|
WgPort int
|
||||||
|
@ -2,6 +2,7 @@ package peer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/wiretrustee/wiretrustee/iface"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
@ -222,7 +223,14 @@ func (conn *Conn) Open() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("connected to peer %s [laddr <-> raddr] [%s <-> %s]", conn.config.Key, remoteConn.LocalAddr().String(), remoteConn.RemoteAddr().String())
|
if conn.proxy.Type() == proxy.TypeNoProxy {
|
||||||
|
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, iface.DefaultWgPort, rhost, iface.DefaultWgPort)
|
||||||
|
} else {
|
||||||
|
log.Infof("connected to peer %s [laddr <-> raddr] [%s <-> %s]", conn.config.Key, remoteConn.LocalAddr().String(), remoteConn.RemoteAddr().String())
|
||||||
|
}
|
||||||
|
|
||||||
// wait until connection disconnected or has been closed externally (upper layer, e.g. engine)
|
// wait until connection disconnected or has been closed externally (upper layer, e.g. engine)
|
||||||
select {
|
select {
|
||||||
@ -235,16 +243,65 @@ func (conn *Conn) Open() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// useProxy determines whether a direct connection (without a go proxy) is possible
|
||||||
|
// There are 3 cases: one of the peers has a public IP or both peers are in the same private network
|
||||||
|
// Please note, that this check happens when peers were already able to ping each other using ICE layer.
|
||||||
|
func shouldUseProxy(pair *ice.CandidatePair) bool {
|
||||||
|
remoteIP := net.ParseIP(pair.Remote.Address())
|
||||||
|
myIp := net.ParseIP(pair.Local.Address())
|
||||||
|
remoteIsPublic := IsPublicIP(remoteIP)
|
||||||
|
myIsPublic := IsPublicIP(myIp)
|
||||||
|
|
||||||
|
//one of the hosts has a public IP
|
||||||
|
if remoteIsPublic && pair.Remote.Type() == ice.CandidateTypeHost {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if myIsPublic && pair.Local.Type() == ice.CandidateTypeHost {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if pair.Local.Type() == ice.CandidateTypeHost && pair.Remote.Type() == ice.CandidateTypeHost {
|
||||||
|
if !remoteIsPublic && !myIsPublic {
|
||||||
|
//both hosts are in the same private network
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPublicIP indicates whether IP is public or not.
|
||||||
|
func IsPublicIP(ip net.IP) bool {
|
||||||
|
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsPrivate() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// startProxy starts proxying traffic from/to local Wireguard and sets connection status to StatusConnected
|
// startProxy starts proxying traffic from/to local Wireguard and sets connection status to StatusConnected
|
||||||
func (conn *Conn) startProxy(remoteConn net.Conn) error {
|
func (conn *Conn) startProxy(remoteConn net.Conn) error {
|
||||||
conn.mu.Lock()
|
conn.mu.Lock()
|
||||||
defer conn.mu.Unlock()
|
defer conn.mu.Unlock()
|
||||||
|
|
||||||
conn.proxy = proxy.NewWireguardProxy(conn.config.ProxyConfig)
|
var pair *ice.CandidatePair
|
||||||
err := conn.proxy.Start(remoteConn)
|
pair, err := conn.agent.GetSelectedCandidatePair()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useProxy := shouldUseProxy(pair)
|
||||||
|
var p proxy.Proxy
|
||||||
|
if useProxy {
|
||||||
|
p = proxy.NewWireguardProxy(conn.config.ProxyConfig)
|
||||||
|
} else {
|
||||||
|
p = proxy.NewNoProxy(conn.config.ProxyConfig)
|
||||||
|
}
|
||||||
|
conn.proxy = p
|
||||||
|
err = p.Start(remoteConn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
conn.status = StatusConnected
|
conn.status = StatusConnected
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -66,3 +66,7 @@ func (p *DummyProxy) Start(remoteConn net.Conn) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *DummyProxy) Type() Type {
|
||||||
|
return TypeDummy
|
||||||
|
}
|
||||||
|
49
client/internal/proxy/noproxy.go
Normal file
49
client/internal/proxy/noproxy.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/wiretrustee/wiretrustee/iface"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NoProxy is used when there is no need for a proxy between ICE and Wireguard.
|
||||||
|
// This is possible in either of these cases:
|
||||||
|
// - peers are in the same local network
|
||||||
|
// - one of the peers has a public static IP (host)
|
||||||
|
// NoProxy will just update remote peer with a remote host and fixed Wireguard port (r.g. 51820).
|
||||||
|
// In order NoProxy to work, Wireguard port has to be fixed for the time being.
|
||||||
|
type NoProxy struct {
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNoProxy(config Config) *NoProxy {
|
||||||
|
return &NoProxy{config: config}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *NoProxy) Close() error {
|
||||||
|
// noop
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start just updates Wireguard peer with the remote IP and default Wireguard port
|
||||||
|
func (p *NoProxy) Start(remoteConn net.Conn) error {
|
||||||
|
|
||||||
|
log.Debugf("using NoProxy while connecting to peer %s", p.config.RemoteKey)
|
||||||
|
addr, err := net.ResolveUDPAddr("udp", remoteConn.RemoteAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
addr.Port = iface.DefaultWgPort
|
||||||
|
err = p.config.WgInterface.UpdatePeer(p.config.RemoteKey, p.config.AllowedIps, DefaultWgKeepAlive,
|
||||||
|
addr, p.config.PreSharedKey)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *NoProxy) Type() Type {
|
||||||
|
return TypeNoProxy
|
||||||
|
}
|
@ -10,6 +10,14 @@ import (
|
|||||||
|
|
||||||
const DefaultWgKeepAlive = 25 * time.Second
|
const DefaultWgKeepAlive = 25 * time.Second
|
||||||
|
|
||||||
|
type Type string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeNoProxy Type = "NoProxy"
|
||||||
|
TypeWireguard Type = "Wireguard"
|
||||||
|
TypeDummy Type = "Dummy"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
WgListenAddr string
|
WgListenAddr string
|
||||||
RemoteKey string
|
RemoteKey string
|
||||||
@ -22,4 +30,5 @@ type Proxy interface {
|
|||||||
io.Closer
|
io.Closer
|
||||||
// Start creates a local remoteConn and starts proxying data from/to remoteConn
|
// Start creates a local remoteConn and starts proxying data from/to remoteConn
|
||||||
Start(remoteConn net.Conn) error
|
Start(remoteConn net.Conn) error
|
||||||
|
Type() Type
|
||||||
}
|
}
|
||||||
|
@ -122,3 +122,7 @@ func (p *WireguardProxy) proxyToLocal() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *WireguardProxy) Type() Type {
|
||||||
|
return TypeWireguard
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultMTU = 1280
|
DefaultMTU = 1280
|
||||||
|
DefaultWgPort = 51820
|
||||||
)
|
)
|
||||||
|
|
||||||
// WGIface represents a interface instance
|
// WGIface represents a interface instance
|
||||||
|
Loading…
x
Reference in New Issue
Block a user