wgengine/magicsock: run test DERP in mode where only disco packets allowed
So we don't accidentally pass a NAT traversal test by having DERP pick up our slack when we really just wanted DERP as an OOB messaging channel.
This commit is contained in:
parent
75e1cc1dd5
commit
a6559a8924
|
@ -26,6 +26,7 @@ import (
|
||||||
|
|
||||||
"golang.org/x/crypto/nacl/box"
|
"golang.org/x/crypto/nacl/box"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
"tailscale.com/disco"
|
||||||
"tailscale.com/metrics"
|
"tailscale.com/metrics"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
|
@ -47,6 +48,12 @@ type Server struct {
|
||||||
// before failing when writing to a client.
|
// before failing when writing to a client.
|
||||||
WriteTimeout time.Duration
|
WriteTimeout time.Duration
|
||||||
|
|
||||||
|
// OnlyDisco controls whether, for tests, non-discovery packets
|
||||||
|
// are dropped. This is used by magicsock tests to verify that
|
||||||
|
// NAT traversal works (using DERP for out-of-band messaging)
|
||||||
|
// but the packets themselves aren't going via DERP.
|
||||||
|
OnlyDisco bool
|
||||||
|
|
||||||
privateKey key.Private
|
privateKey key.Private
|
||||||
publicKey key.Public
|
publicKey key.Public
|
||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
|
@ -547,6 +554,11 @@ func (c *sclient) handleFrameSendPacket(ft frameType, fl uint32) error {
|
||||||
return fmt.Errorf("client %x: recvPacket: %v", c.key, err)
|
return fmt.Errorf("client %x: recvPacket: %v", c.key, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.OnlyDisco && !disco.LooksLikeDiscoWrapper(contents) {
|
||||||
|
s.packetsDropped.Add(1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var fwd PacketForwarder
|
var fwd PacketForwarder
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
dst := s.clients[dstKey]
|
dst := s.clients[dstKey]
|
||||||
|
|
|
@ -31,6 +31,8 @@ import (
|
||||||
// Magic is the 6 byte header of all discovery messages.
|
// Magic is the 6 byte header of all discovery messages.
|
||||||
const Magic = "TS💬" // 6 bytes: 0x54 53 f0 9f 92 ac
|
const Magic = "TS💬" // 6 bytes: 0x54 53 f0 9f 92 ac
|
||||||
|
|
||||||
|
const keyLen = 32
|
||||||
|
|
||||||
// NonceLen is the length of the nonces used by nacl secretboxes.
|
// NonceLen is the length of the nonces used by nacl secretboxes.
|
||||||
const NonceLen = 24
|
const NonceLen = 24
|
||||||
|
|
||||||
|
@ -46,6 +48,15 @@ const v0 = byte(0)
|
||||||
|
|
||||||
var errShort = errors.New("short message")
|
var errShort = errors.New("short message")
|
||||||
|
|
||||||
|
// LooksLikeDiscoWrapper reports whether p looks like it's a packet
|
||||||
|
// containing an encrypted disco message.
|
||||||
|
func LooksLikeDiscoWrapper(p []byte) bool {
|
||||||
|
if len(p) < len(Magic)+keyLen+NonceLen {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return string(p[:len(Magic)]) == Magic
|
||||||
|
}
|
||||||
|
|
||||||
// Parse parses the encrypted part of the message from inside the
|
// Parse parses the encrypted part of the message from inside the
|
||||||
// nacl secretbox.
|
// nacl secretbox.
|
||||||
func Parse(p []byte) (Message, error) {
|
func Parse(p []byte) (Message, error) {
|
||||||
|
|
|
@ -243,19 +243,20 @@ func parseCIDR(t *testing.T, addr string) wgcfg.CIDR {
|
||||||
return cidr
|
return cidr
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDERP(t *testing.T, logf logger.Logf) (s *derp.Server, addr *net.TCPAddr, cleanupFn func()) {
|
func runDERP(t *testing.T, logf logger.Logf, onlyDisco bool) (s *derp.Server, addr *net.TCPAddr, cleanupFn func()) {
|
||||||
var serverPrivateKey key.Private
|
var serverPrivateKey key.Private
|
||||||
if _, err := crand.Read(serverPrivateKey[:]); err != nil {
|
if _, err := crand.Read(serverPrivateKey[:]); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s = derp.NewServer(serverPrivateKey, logf)
|
s = derp.NewServer(serverPrivateKey, logf)
|
||||||
|
s.OnlyDisco = onlyDisco
|
||||||
|
|
||||||
httpsrv := httptest.NewUnstartedServer(derphttp.Handler(s))
|
httpsrv := httptest.NewUnstartedServer(derphttp.Handler(s))
|
||||||
httpsrv.Config.ErrorLog = logger.StdLogger(logf)
|
httpsrv.Config.ErrorLog = logger.StdLogger(logf)
|
||||||
httpsrv.Config.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
|
httpsrv.Config.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
|
||||||
httpsrv.StartTLS()
|
httpsrv.StartTLS()
|
||||||
logf("DERP server URL: %s", httpsrv.URL)
|
logf("DERP server URL: %s (onlyDisco=%v)", httpsrv.URL, onlyDisco)
|
||||||
|
|
||||||
cleanupFn = func() {
|
cleanupFn = func() {
|
||||||
httpsrv.CloseClientConnections()
|
httpsrv.CloseClientConnections()
|
||||||
|
@ -413,11 +414,13 @@ func testTwoDevicePing(t *testing.T, d *devices) {
|
||||||
rc := tstest.NewResourceCheck()
|
rc := tstest.NewResourceCheck()
|
||||||
defer rc.Assert(t)
|
defer rc.Assert(t)
|
||||||
|
|
||||||
|
usingNatLab := d.m1 != (nettype.Std{})
|
||||||
|
|
||||||
// This gets reassigned inside every test, so that the connections
|
// This gets reassigned inside every test, so that the connections
|
||||||
// all log using the "current" t.Logf function. Sigh.
|
// all log using the "current" t.Logf function. Sigh.
|
||||||
logf, setT := makeNestable(t)
|
logf, setT := makeNestable(t)
|
||||||
|
|
||||||
derpServer, derpAddr, derpCleanupFn := runDERP(t, logf)
|
derpServer, derpAddr, derpCleanupFn := runDERP(t, logf, usingNatLab)
|
||||||
defer derpCleanupFn()
|
defer derpCleanupFn()
|
||||||
|
|
||||||
stunAddr, stunCleanupFn := stuntest.ServeWithPacketListener(t, d.stun)
|
stunAddr, stunCleanupFn := stuntest.ServeWithPacketListener(t, d.stun)
|
||||||
|
|
Loading…
Reference in New Issue