mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-30 18:41:37 -07:00
[client, proxy] Remove lazy connection exclusions and run Rosenpass on the embedded proxy (#6763)
* Run lazy connection manager for rosenpass peers * Treat forward-target peers as normal lazy connections * Run Rosenpass in permissive mode on the embedded proxy
This commit is contained in:
@@ -85,6 +85,11 @@ type Options struct {
|
|||||||
DisableIPv6 bool
|
DisableIPv6 bool
|
||||||
// BlockInbound blocks all inbound connections from peers
|
// BlockInbound blocks all inbound connections from peers
|
||||||
BlockInbound bool
|
BlockInbound bool
|
||||||
|
// EnableRosenpass enables the Rosenpass post-quantum key exchange.
|
||||||
|
EnableRosenpass bool
|
||||||
|
// RosenpassPermissive lets a Rosenpass-enabled peer still connect to peers
|
||||||
|
// that do not run Rosenpass (falling back to the plain WireGuard PSK).
|
||||||
|
RosenpassPermissive bool
|
||||||
// BlockLANAccess blocks the embedded peer from reaching the host's
|
// BlockLANAccess blocks the embedded peer from reaching the host's
|
||||||
// LAN (RFC 1918, link-local, loopback) when it's used as a routing
|
// LAN (RFC 1918, link-local, loopback) when it's used as a routing
|
||||||
// peer. Mirrors profilemanager.ConfigInput.BlockLANAccess. Useful
|
// peer. Mirrors profilemanager.ConfigInput.BlockLANAccess. Useful
|
||||||
@@ -210,6 +215,8 @@ func New(opts Options) (*Client, error) {
|
|||||||
DisableIPv6: &opts.DisableIPv6,
|
DisableIPv6: &opts.DisableIPv6,
|
||||||
BlockInbound: &opts.BlockInbound,
|
BlockInbound: &opts.BlockInbound,
|
||||||
BlockLANAccess: &opts.BlockLANAccess,
|
BlockLANAccess: &opts.BlockLANAccess,
|
||||||
|
RosenpassEnabled: &opts.EnableRosenpass,
|
||||||
|
RosenpassPermissive: &opts.RosenpassPermissive,
|
||||||
WireguardPort: opts.WireguardPort,
|
WireguardPort: opts.WireguardPort,
|
||||||
MTU: opts.MTU,
|
MTU: opts.MTU,
|
||||||
DNSLabels: parsedLabels,
|
DNSLabels: parsedLabels,
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ type ConnMgr struct {
|
|||||||
statusRecorder *peer.Status
|
statusRecorder *peer.Status
|
||||||
iface lazyconn.WGIface
|
iface lazyconn.WGIface
|
||||||
force lazyForce
|
force lazyForce
|
||||||
rosenpassEnabled bool
|
|
||||||
// remoteLazyEnabled caches the account-wide lazy feature flag from management.
|
// remoteLazyEnabled caches the account-wide lazy feature flag from management.
|
||||||
// It is the default for peers that do not carry a per-peer lazy hint.
|
// It is the default for peers that do not carry a per-peer lazy hint.
|
||||||
remoteLazyEnabled bool
|
remoteLazyEnabled bool
|
||||||
@@ -79,7 +78,6 @@ func NewConnMgr(engineConfig *EngineConfig, statusRecorder *peer.Status, peerSto
|
|||||||
statusRecorder: statusRecorder,
|
statusRecorder: statusRecorder,
|
||||||
iface: iface,
|
iface: iface,
|
||||||
force: resolveLazyForce(engineConfig.LazyConnection),
|
force: resolveLazyForce(engineConfig.LazyConnection),
|
||||||
rosenpassEnabled: engineConfig.RosenpassEnabled,
|
|
||||||
}
|
}
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
@@ -87,19 +85,14 @@ func NewConnMgr(engineConfig *EngineConfig, statusRecorder *peer.Status, peerSto
|
|||||||
// Start initializes the connection manager. The lazy connection manager always runs so that
|
// Start initializes the connection manager. The lazy connection manager always runs so that
|
||||||
// per-peer lazy defaults (e.g. proxy peers) work even when the account flag is off; the
|
// per-peer lazy defaults (e.g. proxy peers) work even when the account flag is off; the
|
||||||
// account flag and the local override decide the default lazy state per peer (see
|
// account flag and the local override decide the default lazy state per peer (see
|
||||||
// PeerLazyDefault). Rosenpass is the only condition that disables it.
|
// PeerLazyDefault). Rosenpass peers stay lazy-capable too: their connections just never idle
|
||||||
|
// on their own, since rosenpass rekey traffic keeps them active.
|
||||||
func (e *ConnMgr) Start(ctx context.Context) {
|
func (e *ConnMgr) Start(ctx context.Context) {
|
||||||
if e.lazyConnMgr != nil {
|
if e.lazyConnMgr != nil {
|
||||||
log.Errorf("lazy connection manager is already started")
|
log.Errorf("lazy connection manager is already started")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.rosenpassEnabled {
|
|
||||||
log.Warnf("rosenpass is enabled, lazy connection manager will not be started")
|
|
||||||
e.statusRecorder.UpdateLazyConnection(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
e.initLazyManager(ctx)
|
e.initLazyManager(ctx)
|
||||||
e.statusRecorder.UpdateLazyConnection(e.PeerLazyDefault(mgmProto.LazyState_LazyStateDefault))
|
e.statusRecorder.UpdateLazyConnection(e.PeerLazyDefault(mgmProto.LazyState_LazyStateDefault))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ func TestToExcludedLazyPeers(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
e := &Engine{connMgr: &ConnMgr{force: tt.force, remoteLazyEnabled: tt.remoteEnabled}}
|
e := &Engine{connMgr: &ConnMgr{force: tt.force, remoteLazyEnabled: tt.remoteEnabled}}
|
||||||
got := e.toExcludedLazyPeers(nil, peers)
|
got := e.toExcludedLazyPeers(peers)
|
||||||
|
|
||||||
if len(got) != len(tt.want) {
|
if len(got) != len(tt.want) {
|
||||||
t.Fatalf("toExcludedLazyPeers() = %v, want %v", got, tt.want)
|
t.Fatalf("toExcludedLazyPeers() = %v, want %v", got, tt.want)
|
||||||
|
|||||||
@@ -833,7 +833,7 @@ func (e *Engine) blockLanAccess() {
|
|||||||
|
|
||||||
// modifyPeers updates peers that have been modified (e.g. IP address has been changed).
|
// modifyPeers updates peers that have been modified (e.g. IP address has been changed).
|
||||||
// It closes the existing connection, removes it from the peerConns map, and creates a new one.
|
// It closes the existing connection, removes it from the peerConns map, and creates a new one.
|
||||||
func (e *Engine) modifyPeers(peersUpdate []*mgmProto.RemotePeerConfig, forwardingRules []firewallManager.ForwardRule) error {
|
func (e *Engine) modifyPeers(peersUpdate []*mgmProto.RemotePeerConfig) error {
|
||||||
|
|
||||||
// first, check if peers have been modified
|
// first, check if peers have been modified
|
||||||
var modified []*mgmProto.RemotePeerConfig
|
var modified []*mgmProto.RemotePeerConfig
|
||||||
@@ -872,8 +872,7 @@ func (e *Engine) modifyPeers(peersUpdate []*mgmProto.RemotePeerConfig, forwardin
|
|||||||
}
|
}
|
||||||
// third, add the peer connections again
|
// third, add the peer connections again
|
||||||
for _, p := range modified {
|
for _, p := range modified {
|
||||||
err := e.addNewPeer(p, forwardingRules)
|
if err := e.addNewPeer(p); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1566,8 +1565,7 @@ func (e *Engine) updateNetworkMap(networkMap *mgmProto.NetworkMap) error {
|
|||||||
|
|
||||||
// Ingress forward rules
|
// Ingress forward rules
|
||||||
done = e.phase("forward_rules")
|
done = e.phase("forward_rules")
|
||||||
forwardingRules, err := e.updateForwardRules(networkMap.GetForwardingRules())
|
if _, err := e.updateForwardRules(networkMap.GetForwardingRules()); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to update forward rules, err: %v", err)
|
log.Errorf("failed to update forward rules, err: %v", err)
|
||||||
}
|
}
|
||||||
done()
|
done()
|
||||||
@@ -1578,14 +1576,14 @@ func (e *Engine) updateNetworkMap(networkMap *mgmProto.NetworkMap) error {
|
|||||||
e.updateOfflinePeers(networkMap.GetOfflinePeers())
|
e.updateOfflinePeers(networkMap.GetOfflinePeers())
|
||||||
done()
|
done()
|
||||||
|
|
||||||
remotePeers, err := e.reconcilePeers(networkMap, forwardingRules)
|
remotePeers, err := e.reconcilePeers(networkMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// must set the exclude list after the peers are added. Without it the manager can not figure out the peers parameters from the store
|
// must set the exclude list after the peers are added. Without it the manager can not figure out the peers parameters from the store
|
||||||
done = e.phase("lazy_exclude")
|
done = e.phase("lazy_exclude")
|
||||||
e.connMgr.SetExcludeList(e.ctx, e.toExcludedLazyPeers(forwardingRules, remotePeers))
|
e.connMgr.SetExcludeList(e.ctx, e.toExcludedLazyPeers(remotePeers))
|
||||||
done()
|
done()
|
||||||
|
|
||||||
e.networkSerial = serial
|
e.networkSerial = serial
|
||||||
@@ -1595,10 +1593,8 @@ func (e *Engine) updateNetworkMap(networkMap *mgmProto.NetworkMap) error {
|
|||||||
|
|
||||||
// reconcilePeers applies the remote peer list from the network map (removing,
|
// reconcilePeers applies the remote peer list from the network map (removing,
|
||||||
// modifying and adding peers, then updating SSH config) and returns the remote
|
// modifying and adding peers, then updating SSH config) and returns the remote
|
||||||
// peers with our own peer filtered out, for use by later sync steps. The
|
// peers with our own peer filtered out, for use by later sync steps.
|
||||||
// forwarding rules are used to decide whether a newly added peer needs an
|
func (e *Engine) reconcilePeers(networkMap *mgmProto.NetworkMap) ([]*mgmProto.RemotePeerConfig, error) {
|
||||||
// always-active connection.
|
|
||||||
func (e *Engine) reconcilePeers(networkMap *mgmProto.NetworkMap, forwardingRules []firewallManager.ForwardRule) ([]*mgmProto.RemotePeerConfig, error) {
|
|
||||||
// Filter out own peer from the remote peers list
|
// Filter out own peer from the remote peers list
|
||||||
localPubKey := e.config.WgPrivateKey.PublicKey().String()
|
localPubKey := e.config.WgPrivateKey.PublicKey().String()
|
||||||
remotePeers := make([]*mgmProto.RemotePeerConfig, 0, len(networkMap.GetRemotePeers()))
|
remotePeers := make([]*mgmProto.RemotePeerConfig, 0, len(networkMap.GetRemotePeers()))
|
||||||
@@ -1626,14 +1622,14 @@ func (e *Engine) reconcilePeers(networkMap *mgmProto.NetworkMap, forwardingRules
|
|||||||
}
|
}
|
||||||
|
|
||||||
done = e.phase("modified_peers")
|
done = e.phase("modified_peers")
|
||||||
err = e.modifyPeers(remotePeers, forwardingRules)
|
err = e.modifyPeers(remotePeers)
|
||||||
done()
|
done()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
done = e.phase("added_peers")
|
done = e.phase("added_peers")
|
||||||
err = e.addNewPeers(remotePeers, forwardingRules)
|
err = e.addNewPeers(remotePeers)
|
||||||
done()
|
done()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1829,10 +1825,9 @@ func addrToString(addr netip.Addr) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addNewPeers adds peers that were not know before but arrived from the Management service with the update
|
// addNewPeers adds peers that were not know before but arrived from the Management service with the update
|
||||||
func (e *Engine) addNewPeers(peersUpdate []*mgmProto.RemotePeerConfig, forwardingRules []firewallManager.ForwardRule) error {
|
func (e *Engine) addNewPeers(peersUpdate []*mgmProto.RemotePeerConfig) error {
|
||||||
for _, p := range peersUpdate {
|
for _, p := range peersUpdate {
|
||||||
err := e.addNewPeer(p, forwardingRules)
|
if err := e.addNewPeer(p); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1840,8 +1835,8 @@ func (e *Engine) addNewPeers(peersUpdate []*mgmProto.RemotePeerConfig, forwardin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addNewPeer add peer if connection doesn't exist. A peer that is not lazy by
|
// addNewPeer add peer if connection doesn't exist. A peer that is not lazy by
|
||||||
// policy (or is a forwarder) gets an always-active connection instead.
|
// policy gets an always-active connection instead.
|
||||||
func (e *Engine) addNewPeer(peerConfig *mgmProto.RemotePeerConfig, forwardingRules []firewallManager.ForwardRule) error {
|
func (e *Engine) addNewPeer(peerConfig *mgmProto.RemotePeerConfig) error {
|
||||||
peerKey := peerConfig.GetWgPubKey()
|
peerKey := peerConfig.GetWgPubKey()
|
||||||
peerIPs := make([]netip.Prefix, 0, len(peerConfig.GetAllowedIps()))
|
peerIPs := make([]netip.Prefix, 0, len(peerConfig.GetAllowedIps()))
|
||||||
if _, ok := e.peerStore.PeerConn(peerKey); ok {
|
if _, ok := e.peerStore.PeerConn(peerKey); ok {
|
||||||
@@ -1875,7 +1870,8 @@ func (e *Engine) addNewPeer(peerConfig *mgmProto.RemotePeerConfig, forwardingRul
|
|||||||
log.Warnf("error adding peer %s to status recorder, got error: %v", peerKey, err)
|
log.Warnf("error adding peer %s to status recorder, got error: %v", peerKey, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if exists := e.connMgr.AddPeerConn(e.ctx, peerKey, conn, e.isPermanentPeer(peerConfig, forwardingRules)); exists {
|
permanent := !e.connMgr.PeerLazyDefault(peerConfig.GetLazyState())
|
||||||
|
if exists := e.connMgr.AddPeerConn(e.ctx, peerKey, conn, permanent); exists {
|
||||||
conn.Close(false)
|
conn.Close(false)
|
||||||
return fmt.Errorf("peer already exists: %s", peerKey)
|
return fmt.Errorf("peer already exists: %s", peerKey)
|
||||||
}
|
}
|
||||||
@@ -2668,55 +2664,18 @@ func (e *Engine) updateForwardRules(rules []*mgmProto.ForwardingRule) ([]firewal
|
|||||||
}
|
}
|
||||||
|
|
||||||
// toExcludedLazyPeers returns the peers that must have an always-active
|
// toExcludedLazyPeers returns the peers that must have an always-active
|
||||||
// connection, so the caller can reconcile the lazy manager's exclude list.
|
// connection: those that are not lazy by policy (the per-peer lazy state or the
|
||||||
func (e *Engine) toExcludedLazyPeers(rules []firewallManager.ForwardRule, peers []*mgmProto.RemotePeerConfig) map[string]bool {
|
// account flag, subject to the local override).
|
||||||
|
func (e *Engine) toExcludedLazyPeers(peers []*mgmProto.RemotePeerConfig) map[string]bool {
|
||||||
excludedPeers := make(map[string]bool)
|
excludedPeers := make(map[string]bool)
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
if e.isPermanentPeer(p, rules) {
|
if !e.connMgr.PeerLazyDefault(p.GetLazyState()) {
|
||||||
excludedPeers[p.GetWgPubKey()] = true
|
excludedPeers[p.GetWgPubKey()] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return excludedPeers
|
return excludedPeers
|
||||||
}
|
}
|
||||||
|
|
||||||
// isPermanentPeer reports whether a peer needs an always-active connection: it
|
|
||||||
// is not lazy by policy (the per-peer lazy hint or account flag, subject to the
|
|
||||||
// local override), or it is an ingress forward target. Inbound forwarded traffic
|
|
||||||
// is initiated remotely and cannot wake a lazy connection, so the peer routing
|
|
||||||
// the target must stay permanently connected.
|
|
||||||
func (e *Engine) isPermanentPeer(p *mgmProto.RemotePeerConfig, rules []firewallManager.ForwardRule) bool {
|
|
||||||
if !e.connMgr.PeerLazyDefault(p.GetLazyState()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match against the incoming config's AllowedIPs rather than the peer store:
|
|
||||||
// isPermanentPeer runs in addNewPeer before the peer is in the store, so a
|
|
||||||
// store lookup would miss a forward target and register it as lazy.
|
|
||||||
prefixes := make([]netip.Prefix, 0, len(p.GetAllowedIps()))
|
|
||||||
for _, ipStr := range p.GetAllowedIps() {
|
|
||||||
if prefix, err := netip.ParsePrefix(ipStr); err == nil {
|
|
||||||
prefixes = append(prefixes, prefix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, r := range rules {
|
|
||||||
if prefixesContain(prefixes, r.TranslatedAddress) {
|
|
||||||
log.Infof("exclude forwarder peer from lazy connection: %s", p.GetWgPubKey())
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// prefixesContain reports whether addr falls within any of the prefixes.
|
|
||||||
func prefixesContain(prefixes []netip.Prefix, addr netip.Addr) bool {
|
|
||||||
for _, prefix := range prefixes {
|
|
||||||
if prefix.Contains(addr) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// isChecksEqual checks if two slices of checks are equal.
|
// isChecksEqual checks if two slices of checks are equal.
|
||||||
func isChecksEqual(checks1, checks2 []*mgmProto.Checks) bool {
|
func isChecksEqual(checks1, checks2 []*mgmProto.Checks) bool {
|
||||||
normalize := func(checks []*mgmProto.Checks) []string {
|
normalize := func(checks []*mgmProto.Checks) []string {
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/netip"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
firewallManager "github.com/netbirdio/netbird/client/firewall/manager"
|
|
||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
|
||||||
"github.com/netbirdio/netbird/client/internal/peerstore"
|
|
||||||
mgmProto "github.com/netbirdio/netbird/shared/management/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPrefixesContain(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
prefixes []string
|
|
||||||
addr string
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{name: "own overlay /32 matches", prefixes: []string{"100.110.8.145/32"}, addr: "100.110.8.145", want: true},
|
|
||||||
{name: "addr inside routed subnet", prefixes: []string{"10.121.0.0/16"}, addr: "10.121.208.4", want: true},
|
|
||||||
{name: "addr outside subnet", prefixes: []string{"10.121.0.0/16"}, addr: "10.122.0.1", want: false},
|
|
||||||
{name: "different /32", prefixes: []string{"100.110.8.145/32"}, addr: "100.110.8.146", want: false},
|
|
||||||
{name: "ipv6 /128 matches", prefixes: []string{"fd00::1/128"}, addr: "fd00::1", want: true},
|
|
||||||
{name: "no prefixes", prefixes: nil, addr: "10.121.208.4", want: false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
prefixes := make([]netip.Prefix, 0, len(tt.prefixes))
|
|
||||||
for _, p := range tt.prefixes {
|
|
||||||
prefixes = append(prefixes, netip.MustParsePrefix(p))
|
|
||||||
}
|
|
||||||
require.Equal(t, tt.want, prefixesContain(prefixes, netip.MustParseAddr(tt.addr)))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestToExcludedLazyPeers_ForwardTarget guards a regression: the forward-target
|
|
||||||
// peer (the peer routing a ForwardRule.TranslatedAddress) must be excluded from
|
|
||||||
// lazy connections, matched via the peer's already-parsed AllowedIPs.
|
|
||||||
func TestToExcludedLazyPeers_ForwardTarget(t *testing.T) {
|
|
||||||
const targetPeerKey = "cccccccccccccccccccccccccccccccccccccccccc0="
|
|
||||||
const otherPeerKey = "dddddddddddddddddddddddddddddddddddddddddd0="
|
|
||||||
|
|
||||||
store := peerstore.NewConnStore()
|
|
||||||
store.AddPeerConn(targetPeerKey, newTestConn(t, targetPeerKey, "100.110.8.145/32"))
|
|
||||||
store.AddPeerConn(otherPeerKey, newTestConn(t, otherPeerKey, "100.110.9.10/32"))
|
|
||||||
|
|
||||||
// Lazy on for normal peers, so the only exclusion under test is the forward target.
|
|
||||||
e := &Engine{peerStore: store, connMgr: &ConnMgr{force: lazyForceOn}}
|
|
||||||
|
|
||||||
peers := []*mgmProto.RemotePeerConfig{
|
|
||||||
{WgPubKey: targetPeerKey, AllowedIps: []string{"100.110.8.145/32"}},
|
|
||||||
{WgPubKey: otherPeerKey, AllowedIps: []string{"100.110.9.10/32"}},
|
|
||||||
}
|
|
||||||
rules := []firewallManager.ForwardRule{
|
|
||||||
{TranslatedAddress: netip.MustParseAddr("100.110.8.145")},
|
|
||||||
}
|
|
||||||
|
|
||||||
excluded := e.toExcludedLazyPeers(rules, peers)
|
|
||||||
|
|
||||||
require.True(t, excluded[targetPeerKey], "forward-target peer must be excluded from lazy connections")
|
|
||||||
require.False(t, excluded[otherPeerKey], "non-target peer must not be excluded")
|
|
||||||
require.Len(t, excluded, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestToExcludedLazyPeers_NoRules(t *testing.T) {
|
|
||||||
// Lazy on for normal peers and no forward rules, so nothing is excluded.
|
|
||||||
e := &Engine{peerStore: peerstore.NewConnStore(), connMgr: &ConnMgr{force: lazyForceOn}}
|
|
||||||
|
|
||||||
peers := []*mgmProto.RemotePeerConfig{
|
|
||||||
{WgPubKey: "peer-a", AllowedIps: []string{"100.110.8.145/32"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Empty(t, e.toExcludedLazyPeers(nil, peers))
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTestConn(t *testing.T, key, allowedIP string) *peer.Conn {
|
|
||||||
t.Helper()
|
|
||||||
conn, err := peer.NewConn(peer.ConnConfig{
|
|
||||||
Key: key,
|
|
||||||
WgConfig: peer.WgConfig{AllowedIps: []netip.Prefix{netip.MustParsePrefix(allowedIP)}},
|
|
||||||
}, peer.ServiceDependencies{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
return conn
|
|
||||||
}
|
|
||||||
@@ -30,6 +30,12 @@ import (
|
|||||||
|
|
||||||
const deviceNamePrefix = "ingress-proxy-"
|
const deviceNamePrefix = "ingress-proxy-"
|
||||||
|
|
||||||
|
// envProxyRosenpass toggles Rosenpass (permissive) on the embedded proxy client. Defaults to on.
|
||||||
|
const envProxyRosenpass = "NB_PROXY_ROSENPASS" //nolint:gosec // env var name, not a credential
|
||||||
|
|
||||||
|
// envProxyClientLogLevel sets the embedded NetBird client's log level.
|
||||||
|
const envProxyClientLogLevel = "NB_PROXY_CLIENT_LOG_LEVEL"
|
||||||
|
|
||||||
const clientStopTimeout = 30 * time.Second
|
const clientStopTimeout = 30 * time.Second
|
||||||
|
|
||||||
const createProxyPeerTimeout = 30 * time.Second
|
const createProxyPeerTimeout = 30 * time.Second
|
||||||
@@ -353,11 +359,11 @@ func (n *NetBird) createClientEntry(ctx context.Context, accountID types.Account
|
|||||||
// NB_PROXY_CLIENT_LOG_LEVEL (e.g. "trace") to surface the embedded NetBird
|
// NB_PROXY_CLIENT_LOG_LEVEL (e.g. "trace") to surface the embedded NetBird
|
||||||
// client's relay / signal / handshake detail for local debugging.
|
// client's relay / signal / handshake detail for local debugging.
|
||||||
clientLogLevel := log.WarnLevel.String()
|
clientLogLevel := log.WarnLevel.String()
|
||||||
if v := strings.TrimSpace(os.Getenv("NB_PROXY_CLIENT_LOG_LEVEL")); v != "" {
|
if v := strings.TrimSpace(os.Getenv(envProxyClientLogLevel)); v != "" {
|
||||||
if lvl, err := log.ParseLevel(v); err == nil {
|
if lvl, err := log.ParseLevel(v); err == nil {
|
||||||
clientLogLevel = lvl.String()
|
clientLogLevel = lvl.String()
|
||||||
} else {
|
} else {
|
||||||
n.logger.Warnf("invalid NB_PROXY_CLIENT_LOG_LEVEL %q, using %q: %v", v, clientLogLevel, err)
|
n.logger.Warnf("invalid %s %q, using %q: %v", envProxyClientLogLevel, v, clientLogLevel, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +373,15 @@ func (n *NetBird) createClientEntry(ctx context.Context, accountID types.Account
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Rosenpass runs in permissive mode by default so the embedded proxy can
|
||||||
|
// establish connections with Rosenpass-enabled peers (which otherwise fail
|
||||||
|
// on a PSK mismatch) while still falling back to plain WireGuard for peers
|
||||||
|
// that do not run Rosenpass. Set NB_PROXY_ROSENPASS=false to disable it.
|
||||||
|
rosenpassEnabled := true
|
||||||
|
if v, ok := envBool(envProxyRosenpass, n.logger); ok {
|
||||||
|
rosenpassEnabled = v
|
||||||
|
}
|
||||||
|
|
||||||
// Create embedded NetBird client with the generated private key.
|
// Create embedded NetBird client with the generated private key.
|
||||||
// The peer has already been created via CreateProxyPeer RPC with the public key.
|
// The peer has already been created via CreateProxyPeer RPC with the public key.
|
||||||
wgPort := int(n.clientCfg.WGPort)
|
wgPort := int(n.clientCfg.WGPort)
|
||||||
@@ -376,6 +391,8 @@ func (n *NetBird) createClientEntry(ctx context.Context, accountID types.Account
|
|||||||
PrivateKey: privateKey.String(),
|
PrivateKey: privateKey.String(),
|
||||||
LogLevel: clientLogLevel,
|
LogLevel: clientLogLevel,
|
||||||
BlockInbound: n.clientCfg.BlockInbound,
|
BlockInbound: n.clientCfg.BlockInbound,
|
||||||
|
EnableRosenpass: rosenpassEnabled,
|
||||||
|
RosenpassPermissive: rosenpassEnabled,
|
||||||
// The embedded proxy peer must never be a stepping stone into
|
// The embedded proxy peer must never be a stepping stone into
|
||||||
// the proxy host's LAN: it only exists to reach NetBird mesh
|
// the proxy host's LAN: it only exists to reach NetBird mesh
|
||||||
// targets or, when direct_upstream is set, the host network
|
// targets or, when direct_upstream is set, the host network
|
||||||
@@ -899,6 +916,8 @@ func logEmbedOptions(logger *log.Logger, accountID types.AccountID, serviceID ty
|
|||||||
"mtu": mtu,
|
"mtu": mtu,
|
||||||
"block_inbound": opts.BlockInbound,
|
"block_inbound": opts.BlockInbound,
|
||||||
"block_lan_access": opts.BlockLANAccess,
|
"block_lan_access": opts.BlockLANAccess,
|
||||||
|
"rosenpass_enabled": opts.EnableRosenpass,
|
||||||
|
"rosenpass_permissive": opts.RosenpassPermissive,
|
||||||
"disable_ipv6": opts.DisableIPv6,
|
"disable_ipv6": opts.DisableIPv6,
|
||||||
"disable_client_routes": opts.DisableClientRoutes,
|
"disable_client_routes": opts.DisableClientRoutes,
|
||||||
"no_userspace": opts.NoUserspace,
|
"no_userspace": opts.NoUserspace,
|
||||||
|
|||||||
Reference in New Issue
Block a user