mirror of
https://github.com/netbirdio/netbird.git
synced 2025-07-21 08:22:20 +02:00
fixes the Rosenpass preshared key handling to enable successful WireGuard handshakes when one side is in permissive mode. Key changes include: Updating field accesses from RosenpassPubKey/RosenpassAddr to RosenpassConfig.PubKey/RosenpassConfig.Addr. Modifying the preshared key computation logic to account for permissive mode. Revising peer configuration in the Engine to use the new RosenpassConfig struct.
307 lines
8.0 KiB
Go
307 lines
8.0 KiB
Go
package peer
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/netbirdio/netbird/client/iface"
|
|
"github.com/netbirdio/netbird/client/internal/peer/guard"
|
|
"github.com/netbirdio/netbird/client/internal/peer/ice"
|
|
"github.com/netbirdio/netbird/client/internal/stdnet"
|
|
"github.com/netbirdio/netbird/util"
|
|
semaphoregroup "github.com/netbirdio/netbird/util/semaphore-group"
|
|
)
|
|
|
|
var connConf = ConnConfig{
|
|
Key: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
|
LocalKey: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
|
Timeout: time.Second,
|
|
LocalWgPort: 51820,
|
|
ICEConfig: ice.Config{
|
|
InterfaceBlackList: nil,
|
|
},
|
|
}
|
|
|
|
func TestMain(m *testing.M) {
|
|
_ = util.InitLog("trace", "console")
|
|
code := m.Run()
|
|
os.Exit(code)
|
|
}
|
|
|
|
func TestNewConn_interfaceFilter(t *testing.T) {
|
|
ignore := []string{iface.WgInterfaceDefault, "tun0", "zt", "ZeroTier", "utun", "wg", "ts",
|
|
"Tailscale", "tailscale"}
|
|
|
|
filter := stdnet.InterfaceFilter(ignore)
|
|
|
|
for _, s := range ignore {
|
|
assert.Equal(t, filter(s), false)
|
|
}
|
|
|
|
}
|
|
|
|
func TestConn_GetKey(t *testing.T) {
|
|
swWatcher := guard.NewSRWatcher(nil, nil, nil, connConf.ICEConfig)
|
|
conn, err := NewConn(context.Background(), connConf, nil, nil, nil, nil, swWatcher, semaphoregroup.NewSemaphoreGroup(1))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
got := conn.GetKey()
|
|
|
|
assert.Equal(t, got, connConf.Key, "they should be equal")
|
|
}
|
|
|
|
func TestConn_OnRemoteOffer(t *testing.T) {
|
|
swWatcher := guard.NewSRWatcher(nil, nil, nil, connConf.ICEConfig)
|
|
conn, err := NewConn(context.Background(), connConf, NewRecorder("https://mgm"), nil, nil, nil, swWatcher, semaphoregroup.NewSemaphoreGroup(1))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(2)
|
|
go func() {
|
|
<-conn.handshaker.remoteOffersCh
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
for {
|
|
accepted := conn.OnRemoteOffer(OfferAnswer{
|
|
IceCredentials: IceCredentials{
|
|
UFrag: "test",
|
|
Pwd: "test",
|
|
},
|
|
WgListenPort: 0,
|
|
Version: "",
|
|
})
|
|
if accepted {
|
|
wg.Done()
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
func TestConn_OnRemoteAnswer(t *testing.T) {
|
|
swWatcher := guard.NewSRWatcher(nil, nil, nil, connConf.ICEConfig)
|
|
conn, err := NewConn(context.Background(), connConf, NewRecorder("https://mgm"), nil, nil, nil, swWatcher, semaphoregroup.NewSemaphoreGroup(1))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(2)
|
|
go func() {
|
|
<-conn.handshaker.remoteAnswerCh
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
for {
|
|
accepted := conn.OnRemoteAnswer(OfferAnswer{
|
|
IceCredentials: IceCredentials{
|
|
UFrag: "test",
|
|
Pwd: "test",
|
|
},
|
|
WgListenPort: 0,
|
|
Version: "",
|
|
})
|
|
if accepted {
|
|
wg.Done()
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
wg.Wait()
|
|
}
|
|
func TestConn_Status(t *testing.T) {
|
|
swWatcher := guard.NewSRWatcher(nil, nil, nil, connConf.ICEConfig)
|
|
conn, err := NewConn(context.Background(), connConf, NewRecorder("https://mgm"), nil, nil, nil, swWatcher, semaphoregroup.NewSemaphoreGroup(1))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
tables := []struct {
|
|
name string
|
|
statusIce ConnStatus
|
|
statusRelay ConnStatus
|
|
want ConnStatus
|
|
}{
|
|
{"StatusConnected", StatusConnected, StatusConnected, StatusConnected},
|
|
{"StatusDisconnected", StatusDisconnected, StatusDisconnected, StatusDisconnected},
|
|
{"StatusConnecting", StatusConnecting, StatusConnecting, StatusConnecting},
|
|
{"StatusConnectingIce", StatusConnecting, StatusDisconnected, StatusConnecting},
|
|
{"StatusConnectingIceAlternative", StatusConnecting, StatusConnected, StatusConnected},
|
|
{"StatusConnectingRelay", StatusDisconnected, StatusConnecting, StatusConnecting},
|
|
{"StatusConnectingRelayAlternative", StatusConnected, StatusConnecting, StatusConnected},
|
|
}
|
|
|
|
for _, table := range tables {
|
|
t.Run(table.name, func(t *testing.T) {
|
|
si := NewAtomicConnStatus()
|
|
si.Set(table.statusIce)
|
|
conn.statusICE = si
|
|
|
|
sr := NewAtomicConnStatus()
|
|
sr.Set(table.statusRelay)
|
|
conn.statusRelay = sr
|
|
|
|
got := conn.Status()
|
|
assert.Equal(t, got, table.want, "they should be equal")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConn_presharedKey(t *testing.T) {
|
|
conn1 := Conn{
|
|
config: ConnConfig{
|
|
Key: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
|
LocalKey: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
|
RosenpassConfig: RosenpassConfig{},
|
|
},
|
|
}
|
|
conn2 := Conn{
|
|
config: ConnConfig{
|
|
Key: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
|
LocalKey: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
|
RosenpassConfig: RosenpassConfig{},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
conn1Permissive bool
|
|
conn1RosenpassEnabled bool
|
|
conn2Permissive bool
|
|
conn2RosenpassEnabled bool
|
|
conn1ExpectedInitialKey bool
|
|
conn2ExpectedInitialKey bool
|
|
}{
|
|
{
|
|
conn1Permissive: false,
|
|
conn1RosenpassEnabled: false,
|
|
conn2Permissive: false,
|
|
conn2RosenpassEnabled: false,
|
|
conn1ExpectedInitialKey: false,
|
|
conn2ExpectedInitialKey: false,
|
|
},
|
|
{
|
|
conn1Permissive: false,
|
|
conn1RosenpassEnabled: true,
|
|
conn2Permissive: false,
|
|
conn2RosenpassEnabled: true,
|
|
conn1ExpectedInitialKey: true,
|
|
conn2ExpectedInitialKey: true,
|
|
},
|
|
{
|
|
conn1Permissive: false,
|
|
conn1RosenpassEnabled: true,
|
|
conn2Permissive: false,
|
|
conn2RosenpassEnabled: false,
|
|
conn1ExpectedInitialKey: true,
|
|
conn2ExpectedInitialKey: false,
|
|
},
|
|
{
|
|
conn1Permissive: false,
|
|
conn1RosenpassEnabled: false,
|
|
conn2Permissive: false,
|
|
conn2RosenpassEnabled: true,
|
|
conn1ExpectedInitialKey: false,
|
|
conn2ExpectedInitialKey: true,
|
|
},
|
|
{
|
|
conn1Permissive: true,
|
|
conn1RosenpassEnabled: true,
|
|
conn2Permissive: false,
|
|
conn2RosenpassEnabled: false,
|
|
conn1ExpectedInitialKey: false,
|
|
conn2ExpectedInitialKey: false,
|
|
},
|
|
{
|
|
conn1Permissive: false,
|
|
conn1RosenpassEnabled: false,
|
|
conn2Permissive: true,
|
|
conn2RosenpassEnabled: true,
|
|
conn1ExpectedInitialKey: false,
|
|
conn2ExpectedInitialKey: false,
|
|
},
|
|
{
|
|
conn1Permissive: true,
|
|
conn1RosenpassEnabled: true,
|
|
conn2Permissive: true,
|
|
conn2RosenpassEnabled: true,
|
|
conn1ExpectedInitialKey: true,
|
|
conn2ExpectedInitialKey: true,
|
|
},
|
|
{
|
|
conn1Permissive: false,
|
|
conn1RosenpassEnabled: false,
|
|
conn2Permissive: false,
|
|
conn2RosenpassEnabled: true,
|
|
conn1ExpectedInitialKey: false,
|
|
conn2ExpectedInitialKey: true,
|
|
},
|
|
{
|
|
conn1Permissive: false,
|
|
conn1RosenpassEnabled: true,
|
|
conn2Permissive: true,
|
|
conn2RosenpassEnabled: true,
|
|
conn1ExpectedInitialKey: true,
|
|
conn2ExpectedInitialKey: true,
|
|
},
|
|
}
|
|
|
|
conn1.config.RosenpassConfig.PermissiveMode = true
|
|
for i, test := range tests {
|
|
tcase := i + 1
|
|
t.Run(fmt.Sprintf("Rosenpass test case %d", tcase), func(t *testing.T) {
|
|
conn1.config.RosenpassConfig = RosenpassConfig{}
|
|
conn2.config.RosenpassConfig = RosenpassConfig{}
|
|
|
|
if test.conn1RosenpassEnabled {
|
|
conn1.config.RosenpassConfig.PubKey = []byte("dummykey")
|
|
}
|
|
conn1.config.RosenpassConfig.PermissiveMode = test.conn1Permissive
|
|
|
|
if test.conn2RosenpassEnabled {
|
|
conn2.config.RosenpassConfig.PubKey = []byte("dummykey")
|
|
}
|
|
conn2.config.RosenpassConfig.PermissiveMode = test.conn2Permissive
|
|
|
|
conn1PresharedKey := conn1.presharedKey(conn2.config.RosenpassConfig.PubKey)
|
|
conn2PresharedKey := conn2.presharedKey(conn1.config.RosenpassConfig.PubKey)
|
|
|
|
if test.conn1ExpectedInitialKey {
|
|
if conn1PresharedKey == nil {
|
|
t.Errorf("Case %d: Expected conn1 to have a non-nil key, but got nil", tcase)
|
|
}
|
|
} else {
|
|
if conn1PresharedKey != nil {
|
|
t.Errorf("Case %d: Expected conn1 to have a nil key, but got %v", tcase, conn1PresharedKey)
|
|
}
|
|
}
|
|
|
|
// Assert conn2's key expectation
|
|
if test.conn2ExpectedInitialKey {
|
|
if conn2PresharedKey == nil {
|
|
t.Errorf("Case %d: Expected conn2 to have a non-nil key, but got nil", tcase)
|
|
}
|
|
} else {
|
|
if conn2PresharedKey != nil {
|
|
t.Errorf("Case %d: Expected conn2 to have a nil key, but got %v", tcase, conn2PresharedKey)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|