Skip to content

Commit 6afca0f

Browse files
authored
correctly handle a test packet with a payload longer than the header (#1778)
1 parent 02471b4 commit 6afca0f

2 files changed

Lines changed: 87 additions & 1 deletion

File tree

e2e/echo_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//go:build e2e_testing
2+
// +build e2e_testing
3+
4+
package e2e
5+
6+
import (
7+
"testing"
8+
"time"
9+
10+
"github.com/slackhq/nebula"
11+
"github.com/slackhq/nebula/cert"
12+
"github.com/slackhq/nebula/cert_test"
13+
"github.com/slackhq/nebula/e2e/router"
14+
"github.com/slackhq/nebula/header"
15+
"github.com/slackhq/nebula/udp"
16+
"github.com/stretchr/testify/assert"
17+
"github.com/stretchr/testify/require"
18+
)
19+
20+
func assertTestRequestEchoed(t *testing.T, cipher string) {
21+
ca, _, caKey, _ := cert_test.NewTestCaCert(cert.Version1, cert.Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{})
22+
over := m{"cipher": cipher}
23+
a, aNet, aUdp, _ := newSimpleServer(cert.Version1, ca, caKey, "a", "10.128.0.1/24", over)
24+
b, bNet, bUdp, _ := newSimpleServer(cert.Version1, ca, caKey, "b", "10.128.0.2/24", over)
25+
26+
a.InjectLightHouseAddr(bNet[0].Addr(), bUdp)
27+
b.InjectLightHouseAddr(aNet[0].Addr(), aUdp)
28+
a.Start()
29+
b.Start()
30+
t.Cleanup(func() { a.Stop(); b.Stop() })
31+
r := router.NewR(t, a, b)
32+
defer r.RenderFlow()
33+
34+
assertTunnel(t, aNet[0].Addr(), bNet[0].Addr(), a, b, r)
35+
drainUDPTx(a)
36+
drainUDPTx(b)
37+
38+
payload := []byte("a test payload well over sixteen bytes long, wow it's so very long long long!")
39+
require.Greater(t, len(payload), header.Len)
40+
a.GetF().SendMessageToVpnAddr(header.Test, header.TestRequest, bNet[0].Addr(), payload, make([]byte, 12, 12), make([]byte, udp.MTU))
41+
42+
// Deliver A's request to B; B must echo a reply back
43+
b.InjectUDPPacket(a.GetFromUDP(true))
44+
reply := nextUDPTxOfType(t, b, header.Test, header.TestReply, 2*time.Second)
45+
46+
assert.Equal(t, aUdp, reply.To, "the reply must go back to the requester")
47+
// header + echoed payload + 16-byte AEAD tag: proves the whole payload
48+
// round-tripped rather than being dropped or truncated.
49+
assert.Equal(t, header.Len+len(payload)+16, len(reply.Data), "the full payload must be echoed back")
50+
}
51+
52+
func TestTestRequestEchoesLongPayloadAES(t *testing.T) {
53+
assertTestRequestEchoed(t, "aes")
54+
}
55+
56+
func TestTestRequestEchoesLongPayloadChaChaPoly(t *testing.T) {
57+
assertTestRequestEchoed(t, "chachapoly")
58+
}
59+
60+
// drainUDPTx empties a control's UDP tx queue without blocking.
61+
func drainUDPTx(c *nebula.Control) {
62+
for c.GetFromUDP(false) != nil {
63+
}
64+
}
65+
66+
// nextUDPTxOfType returns the next packet a control transmits whose nebula
67+
// header matches (wantType, wantSub), skipping unrelated packets.
68+
// It fails the test if none arrives within the timeout.
69+
func nextUDPTxOfType(t *testing.T, c *nebula.Control, wantType header.MessageType, wantSub header.MessageSubType, within time.Duration) *udp.Packet {
70+
t.Helper()
71+
ch := c.GetUDPTxChan()
72+
timeout := time.After(within)
73+
for {
74+
select {
75+
case p := <-ch:
76+
var h header.H
77+
if err := h.Parse(p.Data); err == nil && h.Type == wantType && h.Subtype == wantSub {
78+
return p
79+
}
80+
case <-timeout:
81+
t.Fatalf("timed out waiting for a %v/%v packet on the udp tx queue", wantType, wantSub)
82+
return nil
83+
}
84+
}
85+
}

outside.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ func (f *Interface) readOutsidePackets(via ViaSender, out []byte, packet []byte,
150150
case header.TestReply:
151151
// No-op, useful for the Roaming and connectionManager side-effects above
152152
case header.TestRequest:
153-
f.send(header.Test, header.TestReply, ci, hostinfo, out, nb, out)
153+
//recycle the input packet ciphertext as our output buffer
154+
f.send(header.Test, header.TestReply, ci, hostinfo, out, nb, packet)
154155
default:
155156
hostinfo.logger(f.l).Error("IsValidSubType was true, but unexpected test subtype seen", "from", via, "header", h)
156157
return

0 commit comments

Comments
 (0)