magicsock: add some DERP tests

Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
pull/141/head
David Crawshaw 5 years ago committed by David Crawshaw
parent a33419167b
commit a65b2a0efd

@ -6,9 +6,13 @@ package magicsock
import (
"bytes"
crand "crypto/rand"
"crypto/tls"
"fmt"
"log"
"net"
"net/http"
"net/http/httptest"
"strings"
"sync"
"testing"
@ -17,10 +21,15 @@ import (
"github.com/tailscale/wireguard-go/device"
"github.com/tailscale/wireguard-go/tun/tuntest"
"github.com/tailscale/wireguard-go/wgcfg"
"tailscale.com/derp"
"tailscale.com/derp/derphttp"
"tailscale.com/stun"
"tailscale.com/types/key"
)
func TestListen(t *testing.T) {
// TODO(crawshaw): when offline this test spends a while trying to connect to real derp servers.
epCh := make(chan string, 16)
epFunc := func(endpoints []string) {
for _, ep := range endpoints {
@ -221,6 +230,7 @@ func makeConfigs(t *testing.T, ports []uint16) []wgcfg.Config {
Host: "127.0.0.1",
Port: port,
}},
PersistentKeepalive: 25,
}
cfg.Peers = append(cfg.Peers, peer)
}
@ -238,7 +248,51 @@ func parseCIDR(t *testing.T, addr string) wgcfg.CIDR {
return *cidr
}
func runDERP(t *testing.T) (s *derp.Server, addr string, cleanupFn func()) {
var serverPrivateKey key.Private
if _, err := crand.Read(serverPrivateKey[:]); err != nil {
t.Fatal(err)
}
s = derp.NewServer(serverPrivateKey, t.Logf)
// TODO: cleanup httpsrv.CloseClientConnections / Close
httpsrv := httptest.NewUnstartedServer(derphttp.Handler(s))
httpsrv.Config.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
httpsrv.StartTLS()
t.Logf("DERP server URL: %s", httpsrv.URL)
addr = strings.TrimPrefix(httpsrv.URL, "https://")
cleanupFn = func() {
s.Close()
}
return s, addr, cleanupFn
}
func stashDerpers() (cleanupFn func()) {
origDerpHostOfIndex := derpHostOfIndex
origDerpIndexOfHost := derpIndexOfHost
origDerpNodeID := derpNodeID
derpHostOfIndex = map[int]string{}
derpIndexOfHost = map[string]int{}
derpNodeID = nil
return func() {
derpHostOfIndex = origDerpHostOfIndex
derpIndexOfHost = origDerpIndexOfHost
derpNodeID = origDerpNodeID
}
}
func TestTwoDevicePing(t *testing.T) {
// Wipe default DERP list, add local server.
// (Do it now, or derpHost will try to connect to derp1.tailscale.com.)
derpServer, derpAddr, derpCleanupFn := runDERP(t)
defer derpCleanupFn()
defer stashDerpers()()
addDerper(1, derpAddr)
stunAddr, stunCleanupFn := serveSTUN(t)
defer stunCleanupFn()
@ -254,6 +308,10 @@ func TestTwoDevicePing(t *testing.T) {
}
defer conn1.Close()
conn1.derpMu.Lock()
conn1.derpTLSConfig = &tls.Config{InsecureSkipVerify: true}
conn1.derpMu.Unlock()
epCh2 := make(chan []string, 16)
conn2, err := Listen(Options{
STUN: []string{stunAddr.String()},
@ -266,13 +324,24 @@ func TestTwoDevicePing(t *testing.T) {
}
defer conn2.Close()
conn2.derpMu.Lock()
conn2.derpTLSConfig = &tls.Config{InsecureSkipVerify: true}
conn2.derpMu.Unlock()
ports := []uint16{conn1.LocalPort(), conn2.LocalPort()}
cfgs := makeConfigs(t, ports)
uapi1, _ := cfgs[0].ToUAPI()
t.Logf("cfg0: %v", uapi1)
uapi2, _ := cfgs[1].ToUAPI()
t.Logf("cfg1: %v", uapi2)
if err := conn1.SetPrivateKey(cfgs[0].PrivateKey); err != nil {
t.Fatal(err)
}
if err := conn2.SetPrivateKey(cfgs[1].PrivateKey); err != nil {
t.Fatal(err)
}
//uapi1, _ := cfgs[0].ToUAPI()
//t.Logf("cfg0: %v", uapi1)
//uapi2, _ := cfgs[1].ToUAPI()
//t.Logf("cfg1: %v", uapi2)
tun1 := tuntest.NewChannelTUN()
dev1 := device.NewDevice(tun1.TUN(), &device.DeviceOptions{
@ -296,6 +365,7 @@ func TestTwoDevicePing(t *testing.T) {
})
dev2.Up()
//defer dev2.Close() TODO(crawshaw): this hangs
if err := dev2.Reconfig(&cfgs[1]); err != nil {
t.Fatal(err)
}
@ -310,7 +380,7 @@ func TestTwoDevicePing(t *testing.T) {
if !bytes.Equal(msg2to1, msgRecv) {
t.Error("ping did not transit correctly")
}
case <-time.After(1 * time.Second):
case <-time.After(3 * time.Second):
t.Error("ping did not transit")
}
}
@ -324,7 +394,7 @@ func TestTwoDevicePing(t *testing.T) {
if !bytes.Equal(msg1to2, msgRecv) {
t.Error("return ping did not transit correctly")
}
case <-time.After(1 * time.Second):
case <-time.After(3 * time.Second):
t.Error("return ping did not transit")
}
}
@ -341,7 +411,7 @@ func TestTwoDevicePing(t *testing.T) {
if !bytes.Equal(msg1to2, msgRecv) {
t.Error("return ping did not transit correctly")
}
case <-time.After(1 * time.Second):
case <-time.After(3 * time.Second):
t.Error("return ping did not transit")
}
})
@ -354,9 +424,7 @@ func TestTwoDevicePing(t *testing.T) {
ping2(t)
})
t.Run("ping 1.0.0.1 x50", func(t *testing.T) {
const count = 50
pingSeq := func(t *testing.T, count int) {
msg := func(i int) []byte {
b := tuntest.Ping(net.ParseIP("1.0.0.2"), net.ParseIP("1.0.0.1"))
b[len(b)-1] = byte(i) // set seq num
@ -375,9 +443,80 @@ func TestTwoDevicePing(t *testing.T) {
if !bytes.Equal(b, msgRecv) {
t.Errorf("return ping %d did not transit correctly", i)
}
case <-time.After(1 * time.Second):
case <-time.After(3 * time.Second):
t.Fatalf("return ping %d did not transit", i)
}
}
}
t.Run("ping 1.0.0.1 x50", func(t *testing.T) {
pingSeq(t, 50)
})
// Add DERP relay.
derpEp := wgcfg.Endpoint{Host: "127.3.3.40", Port: 1}
ep0 := cfgs[0].Peers[0].Endpoints
ep0 = append([]wgcfg.Endpoint{derpEp}, ep0...)
cfgs[0].Peers[0].Endpoints = ep0
ep1 := cfgs[1].Peers[0].Endpoints
ep1 = append([]wgcfg.Endpoint{derpEp}, ep1...)
cfgs[1].Peers[0].Endpoints = ep1
if err := dev1.Reconfig(&cfgs[0]); err != nil {
t.Fatal(err)
}
if err := dev2.Reconfig(&cfgs[1]); err != nil {
t.Fatal(err)
}
t.Run("add DERP", func(t *testing.T) {
defer func() {
t.Logf("DERP vars: %s", derpServer.ExpVar().String())
}()
pingSeq(t, 20)
})
// Disable real route.
cfgs[0].Peers[0].Endpoints = []wgcfg.Endpoint{derpEp}
cfgs[1].Peers[0].Endpoints = []wgcfg.Endpoint{derpEp}
if err := dev1.Reconfig(&cfgs[0]); err != nil {
t.Fatal(err)
}
if err := dev2.Reconfig(&cfgs[1]); err != nil {
t.Fatal(err)
}
time.Sleep(250 * time.Millisecond) // TODO remove
t.Run("all traffic over DERP", func(t *testing.T) {
defer func() {
t.Logf("DERP vars: %s", derpServer.ExpVar().String())
if t.Failed() || true {
uapi1, _ := cfgs[0].ToUAPI()
t.Logf("cfg0: %v", uapi1)
uapi2, _ := cfgs[1].ToUAPI()
t.Logf("cfg1: %v", uapi2)
}
}()
pingSeq(t, 20)
})
// Put one real route.
cfgs[0].Peers[0].Endpoints = ep0
if ep2 := cfgs[1].Peers[0].Endpoints; len(ep2) != 1 {
t.Errorf("unexpected peer endpoints in dev2: %v", ep2)
}
if err := dev1.Reconfig(&cfgs[0]); err != nil {
t.Fatal(err)
}
if err := dev2.Reconfig(&cfgs[1]); err != nil {
t.Fatal(err)
}
t.Run("one real route is enough thanks to spray", func(t *testing.T) {
pingSeq(t, 50)
ep2 := dev2.Config().Peers[0].Endpoints
if len(ep2) != 2 {
t.Error("handshake spray failed to find real route")
}
})
}

Loading…
Cancel
Save