mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-27 23:09:08 +01:00
Removes confirm. Uses next offer to deliver confirmation/ack of previous round
We clock the next Offer initiation to the OnDataPathRekeyed, so we have 2 minutes ahead of us to do our attempts and stuff before to give up. On failure, we will know because we will not receive a new answer.. but more importantly the wg handshake will fail :D
This commit is contained in:
@@ -3,14 +3,13 @@ package pqkem
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// loopback is a data-path transport: a SendDataPath delivers synchronously to the
|
||||
// peer manager's OnDataPathMessage, attributing it to localID (the sender). The
|
||||
// signalling channel is driven by the test directly via the SignalX methods.
|
||||
// loopback is a data-path transport: SendDataPath delivers synchronously to the peer
|
||||
// manager's OnDataPathMessage, attributing it to localID (the sender). The signalling
|
||||
// channel is driven by the test directly via the SignalX methods.
|
||||
type loopback struct {
|
||||
localID string
|
||||
peer *Manager
|
||||
@@ -49,60 +48,75 @@ func (f *fakeWG) psk(peer string) PSK {
|
||||
return f.psks[peer]
|
||||
}
|
||||
|
||||
func TestManager_ExchangeConverges(t *testing.T) {
|
||||
// pair builds two wired managers (B is the initiator, "bbbb" > "aaaa").
|
||||
func pair(t *testing.T) (dA, dB *Manager, wgA, wgB *fakeWG) {
|
||||
t.Helper()
|
||||
lbA := &loopback{localID: "aaaa"}
|
||||
lbB := &loopback{localID: "bbbb"}
|
||||
wgA := newFakeWG()
|
||||
wgB := newFakeWG()
|
||||
wgA = newFakeWG()
|
||||
wgB = newFakeWG()
|
||||
dA = NewManager("aaaa", lbA, wgA, nil)
|
||||
dB = NewManager("bbbb", lbB, wgB, nil)
|
||||
lbA.peer = dB
|
||||
lbB.peer = dA
|
||||
return dA, dB, wgA, wgB
|
||||
}
|
||||
|
||||
dA := NewManager("aaaa", lbA, wgA, time.Hour, nil)
|
||||
dB := NewManager("bbbb", lbB, wgB, time.Hour, nil)
|
||||
lbA.peer = dB // A's data-path sends -> B receives
|
||||
lbB.peer = dA // B's data-path sends -> A receives
|
||||
|
||||
dA.AddPeer("bbbb")
|
||||
dB.AddPeer("aaaa")
|
||||
defer dA.Stop()
|
||||
defer dB.Stop()
|
||||
|
||||
// Bootstrap over the signalling channel (the test plays the host carrying bytes).
|
||||
// B is the initiator ("bbbb" > "aaaa").
|
||||
// bootstrap runs the signalling offer/answer (the test plays the host carrying bytes).
|
||||
func bootstrap(t *testing.T, dA, dB *Manager) {
|
||||
t.Helper()
|
||||
offer, err := dB.SignalOffer("aaaa")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, offer)
|
||||
|
||||
answer, err := dA.SignalOnOffer("bbbb", offer)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, answer)
|
||||
|
||||
require.NoError(t, dB.SignalOnAnswer("aaaa", answer))
|
||||
}
|
||||
|
||||
// Data path comes up on both sides; this makes B send the confirm over the data
|
||||
// path, converging A.
|
||||
func TestManager_BootstrapDerivesSamePSK(t *testing.T) {
|
||||
dA, dB, wgA, wgB := pair(t)
|
||||
defer dA.Stop()
|
||||
defer dB.Stop()
|
||||
|
||||
bootstrap(t, dA, dB)
|
||||
|
||||
pskA := wgA.psk("bbbb")
|
||||
pskB := wgB.psk("aaaa")
|
||||
require.NotEqual(t, PSK{}, pskA)
|
||||
require.Equal(t, pskB, pskA, "both sides derive the same PSK from the bootstrap exchange")
|
||||
}
|
||||
|
||||
func TestManager_ChainRotatesAndAcks(t *testing.T) {
|
||||
dA, dB, wgA, wgB := pair(t)
|
||||
defer dA.Stop()
|
||||
defer dB.Stop()
|
||||
|
||||
bootstrap(t, dA, dB)
|
||||
psk1 := wgB.psk("aaaa")
|
||||
|
||||
// Data path up on both sides; B chains the next offer (acking exchange 1) over the
|
||||
// data path, which rotates both to a fresh PSK and acknowledges A.
|
||||
dA.OnDataPathRekeyed("bbbb")
|
||||
dB.OnDataPathRekeyed("aaaa")
|
||||
|
||||
pskB := wgB.psk("aaaa")
|
||||
pskA := wgA.psk("bbbb")
|
||||
require.NotEqual(t, PSK{}, pskA, "responder A must have a PSK")
|
||||
require.NotEqual(t, PSK{}, pskB, "initiator B must have a PSK")
|
||||
require.Equal(t, pskB, pskA, "both sides converge on the same PSK")
|
||||
psk2A := wgA.psk("bbbb")
|
||||
psk2B := wgB.psk("aaaa")
|
||||
require.Equal(t, psk2B, psk2A, "both sides converge on the rotated PSK")
|
||||
require.NotEqual(t, psk1, psk2B, "the chain rotated to a new PSK")
|
||||
}
|
||||
|
||||
func TestManager_NonInitiatorReturnsNoOffer(t *testing.T) {
|
||||
dA := NewManager("aaaa", &loopback{localID: "aaaa"}, newFakeWG(), time.Hour, nil)
|
||||
dA.AddPeer("bbbb")
|
||||
dA := NewManager("aaaa", &loopback{localID: "aaaa"}, newFakeWG(), nil)
|
||||
defer dA.Stop()
|
||||
|
||||
// A is NOT the initiator vs "bbbb" -> no offer to send.
|
||||
offer, err := dA.SignalOffer("bbbb")
|
||||
offer, err := dA.SignalOffer("bbbb") // not the initiator vs "bbbb"
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, offer)
|
||||
}
|
||||
|
||||
func TestManager_StopIsIdempotent(t *testing.T) {
|
||||
dA := NewManager("aaaa", &loopback{localID: "aaaa"}, newFakeWG(), time.Hour, nil)
|
||||
dA.AddPeer("bbbb")
|
||||
dA := NewManager("aaaa", &loopback{localID: "aaaa"}, newFakeWG(), nil)
|
||||
dA.Stop()
|
||||
dA.Stop() // must not panic or hang
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user