Files
nebula/handshake/machine_lanes_test.go
T
2026-07-21 10:52:24 -05:00

114 lines
3.5 KiB
Go

package handshake
import (
"net/netip"
"testing"
"time"
"github.com/slackhq/nebula/cert"
ct "github.com/slackhq/nebula/cert_test"
"github.com/slackhq/nebula/header"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// newTestLaneMachine is newTestMachine with a lane advert attached.
func newTestLaneMachine(
t *testing.T,
cs *testCertState,
verifier CertVerifier,
initiator bool,
localIndex uint32,
lanes *LaneDetails,
) *Machine {
t.Helper()
m, err := NewMachine(
cs.version, cs.getCredential,
verifier, func() (uint32, error) { return localIndex, nil },
initiator, header.HandshakeIXPSK0,
lanes,
)
require.NoError(t, err)
return m
}
func doFullLaneHandshake(t *testing.T, initLanes, respLanes *LaneDetails) (initR, respR *Result) {
t.Helper()
ca, _, caKey, _ := ct.NewTestCaCert(
cert.Version2, cert.Curve_CURVE25519, time.Time{}, time.Time{}, nil, nil, nil,
)
caPool := ct.NewTestCAPool(ca)
v := testVerifier(caPool)
initCS := newTestCertState(t, ca, caKey, "initiator", []netip.Prefix{netip.MustParsePrefix("10.0.0.1/24")})
respCS := newTestCertState(t, ca, caKey, "responder", []netip.Prefix{netip.MustParsePrefix("10.0.0.2/24")})
initM := newTestLaneMachine(t, initCS, v, true, 1000, initLanes)
respM := newTestLaneMachine(t, respCS, v, false, 2000, respLanes)
msg1, err := initM.Initiate(nil)
require.NoError(t, err)
resp, respR, err := respM.ProcessPacket(nil, msg1)
require.NoError(t, err)
require.NotNil(t, respR)
_, initR, err = initM.ProcessPacket(nil, resp)
require.NoError(t, err)
require.NotNil(t, initR)
return initR, respR
}
func TestMachineLaneAdvertBothSides(t *testing.T) {
initR, respR := doFullLaneHandshake(t,
&LaneDetails{PortCount: 8, BasePort: 4242},
&LaneDetails{PortCount: 4, BasePort: 5353},
)
// Each side's Result carries the peer's advert.
assert.Equal(t, uint32(4), initR.PeerPortCount)
assert.Equal(t, uint32(5353), initR.PeerBasePort)
assert.Equal(t, uint32(0), initR.PeerLaneIndex)
assert.Equal(t, uint32(8), respR.PeerPortCount)
assert.Equal(t, uint32(4242), respR.PeerBasePort)
assert.Equal(t, uint32(0), respR.PeerLaneIndex)
}
func TestMachineLaneHandshakeCarriesLaneIndex(t *testing.T) {
// A lane handshake: initiator tags its lane number; responder still
// adverts (harmlessly).
initR, respR := doFullLaneHandshake(t,
&LaneDetails{PortCount: 8, BasePort: 4242, LaneIndex: 3},
&LaneDetails{PortCount: 4, BasePort: 5353},
)
assert.Equal(t, uint32(3), respR.PeerLaneIndex)
assert.Equal(t, uint32(0), initR.PeerLaneIndex)
}
func TestMachineLaneAdvertAsymmetric(t *testing.T) {
// Vanilla initiator, multiport responder and vice versa: the nil side
// yields all-zero peer fields on the other end.
initR, respR := doFullLaneHandshake(t, nil, &LaneDetails{PortCount: 4, BasePort: 5353})
assert.Equal(t, uint32(4), initR.PeerPortCount)
assert.Equal(t, uint32(0), respR.PeerPortCount)
assert.Equal(t, uint32(0), respR.PeerBasePort)
initR, respR = doFullLaneHandshake(t, &LaneDetails{PortCount: 8, BasePort: 4242}, nil)
assert.Equal(t, uint32(0), initR.PeerPortCount)
assert.Equal(t, uint32(8), respR.PeerPortCount)
}
func TestMachineLaneAdvertOutOfRangeIgnored(t *testing.T) {
// A BasePort that can't be a real UDP port is ignored, not fatal.
initR, respR := doFullLaneHandshake(t,
&LaneDetails{PortCount: 8, BasePort: 70000},
&LaneDetails{PortCount: 4, BasePort: 5353},
)
assert.Equal(t, uint32(0), respR.PeerPortCount)
assert.Equal(t, uint32(0), respR.PeerBasePort)
// The sane side still negotiates.
assert.Equal(t, uint32(4), initR.PeerPortCount)
}