mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-22 21:39:08 +02:00
The split-key test only checked the manager's decision, so a broken handshaker branch would still pass. The capability test asserted while holding the manager lock, which hangs instead of failing.
75 lines
2.6 KiB
Go
75 lines
2.6 KiB
Go
package peer
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
|
|
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
|
signal "github.com/netbirdio/netbird/shared/signal/client"
|
|
sProto "github.com/netbirdio/netbird/shared/signal/proto"
|
|
)
|
|
|
|
// bootstrapPQ is a fakePQ whose controller decision is set by the test.
|
|
type bootstrapPQ struct {
|
|
fakePQ
|
|
bootstrap bool
|
|
}
|
|
|
|
func (b bootstrapPQ) ShouldSendBootstrapOffer(string) bool { return b.bootstrap }
|
|
|
|
// newControllerHandshaker builds a handshaker for the controller side of a peer pair and
|
|
// records the type of every signalling message it sends.
|
|
func newControllerHandshaker(t *testing.T, pq PQHandshaker) (*Handshaker, func() []sProto.Body_Type) {
|
|
t.Helper()
|
|
var mu sync.Mutex
|
|
var sent []sProto.Body_Type
|
|
client := &signal.MockClient{
|
|
ReadyFunc: func() bool { return true },
|
|
SendFunc: func(msg *sProto.Message) error {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
sent = append(sent, msg.GetBody().GetType())
|
|
return nil
|
|
},
|
|
}
|
|
key, err := wgtypes.GeneratePrivateKey()
|
|
require.NoError(t, err)
|
|
config := ConnConfig{Key: "aaaa", LocalKey: "bbbb", PQ: pq} // LocalKey > Key: controller
|
|
relay := &WorkerRelay{relayManager: &relayClient.Manager{}}
|
|
h := NewHandshaker(log.WithField("test", t.Name()), config, NewSignaler(client, key), nil, relay, nil)
|
|
return h, func() []sProto.Body_Type {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
return append([]sProto.Body_Type(nil), sent...)
|
|
}
|
|
}
|
|
|
|
// TestHandshaker_ControllerReoffersOnResponderOffer drives the responder-originated
|
|
// reconnect through the handshaker: when the KEM manager asks for a fresh bootstrap, the
|
|
// controller replies to the responder's KEM-less offer with its own offer and sends no
|
|
// answer, so the reconnect re-derives one PSK on both sides.
|
|
func TestHandshaker_ControllerReoffersOnResponderOffer(t *testing.T) {
|
|
h, sent := newControllerHandshaker(t, bootstrapPQ{bootstrap: true})
|
|
|
|
h.handleRemoteOffer(OfferAnswer{})
|
|
|
|
assert.Equal(t, []sProto.Body_Type{sProto.Body_OFFER}, sent(),
|
|
"the controller must reply with its own offer, not an answer")
|
|
}
|
|
|
|
// TestHandshaker_ControllerAnswersWhileExchangeInFlight keeps the glare protection: with
|
|
// the controller's own exchange in flight, the responder's offer gets a normal answer.
|
|
func TestHandshaker_ControllerAnswersWhileExchangeInFlight(t *testing.T) {
|
|
h, sent := newControllerHandshaker(t, bootstrapPQ{bootstrap: false})
|
|
|
|
h.handleRemoteOffer(OfferAnswer{})
|
|
|
|
assert.Equal(t, []sProto.Body_Type{sProto.Body_ANSWER}, sent(),
|
|
"with an exchange in flight the controller must answer normally")
|
|
}
|