mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 21:15:39 +00:00
126 lines
2.8 KiB
Go
126 lines
2.8 KiB
Go
|
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
// +build linux
|
||
|
|
||
|
package vms
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"net"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path/filepath"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/gliderlabs/ssh"
|
||
|
"golang.org/x/net/proxy"
|
||
|
"inet.af/netaddr"
|
||
|
"tailscale.com/tstest/integration"
|
||
|
"tailscale.com/tstest/integration/testcontrol"
|
||
|
)
|
||
|
|
||
|
type Harness struct {
|
||
|
testerDialer proxy.Dialer
|
||
|
testerDir string
|
||
|
bins *integration.Binaries
|
||
|
signer ssh.Signer
|
||
|
cs *testcontrol.Server
|
||
|
loginServerURL string
|
||
|
testerV4 netaddr.IP
|
||
|
}
|
||
|
|
||
|
func (h *Harness) Tailscale(t *testing.T, args ...string) []byte {
|
||
|
t.Helper()
|
||
|
|
||
|
args = append([]string{"--socket=" + filepath.Join(h.testerDir, "sock")}, args...)
|
||
|
|
||
|
cmd := exec.Command(h.bins.CLI, args...)
|
||
|
out, err := cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
// makeTestNode creates a userspace tailscaled running in netstack mode that
|
||
|
// enables us to make connections to and from the tailscale network being
|
||
|
// tested. This mutates the Harness to allow tests to dial into the tailscale
|
||
|
// network as well as control the tester's tailscaled.
|
||
|
func (h *Harness) makeTestNode(t *testing.T, bins *integration.Binaries, controlURL string) {
|
||
|
dir := t.TempDir()
|
||
|
h.testerDir = dir
|
||
|
|
||
|
port, err := getProbablyFreePortNumber()
|
||
|
if err != nil {
|
||
|
t.Fatalf("can't get free port: %v", err)
|
||
|
}
|
||
|
|
||
|
cmd := exec.Command(
|
||
|
bins.Daemon,
|
||
|
"--tun=userspace-networking",
|
||
|
"--state="+filepath.Join(dir, "state.json"),
|
||
|
"--socket="+filepath.Join(dir, "sock"),
|
||
|
fmt.Sprintf("--socks5-server=localhost:%d", port),
|
||
|
)
|
||
|
|
||
|
cmd.Env = append(
|
||
|
os.Environ(),
|
||
|
"NOTIFY_SOCKET="+filepath.Join(dir, "notify_socket"),
|
||
|
"TS_LOG_TARGET="+h.loginServerURL,
|
||
|
)
|
||
|
|
||
|
err = cmd.Start()
|
||
|
if err != nil {
|
||
|
t.Fatalf("can't start tailscaled: %v", err)
|
||
|
}
|
||
|
|
||
|
t.Cleanup(func() {
|
||
|
cmd.Process.Kill()
|
||
|
})
|
||
|
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
|
defer cancel()
|
||
|
ticker := time.NewTicker(100 * time.Millisecond)
|
||
|
|
||
|
outer:
|
||
|
for {
|
||
|
select {
|
||
|
case <-ctx.Done():
|
||
|
t.Fatal("timed out waiting for tailscaled to come up")
|
||
|
return
|
||
|
case <-ticker.C:
|
||
|
conn, err := net.Dial("unix", filepath.Join(dir, "sock"))
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
conn.Close()
|
||
|
break outer
|
||
|
}
|
||
|
}
|
||
|
|
||
|
run(t, dir, bins.CLI,
|
||
|
"--socket="+filepath.Join(dir, "sock"),
|
||
|
"up",
|
||
|
"--login-server="+controlURL,
|
||
|
"--hostname=tester",
|
||
|
)
|
||
|
|
||
|
dialer, err := proxy.SOCKS5("tcp", net.JoinHostPort("127.0.0.1", fmt.Sprint(port)), nil, &net.Dialer{})
|
||
|
if err != nil {
|
||
|
t.Fatalf("can't make netstack proxy dialer: %v", err)
|
||
|
}
|
||
|
h.testerDialer = dialer
|
||
|
h.testerV4 = bytes2Netaddr(h.Tailscale(t, "ip", "-4"))
|
||
|
}
|
||
|
|
||
|
func bytes2Netaddr(inp []byte) netaddr.IP {
|
||
|
return netaddr.MustParseIP(string(bytes.TrimSpace(inp)))
|
||
|
}
|