|
|
@@ -68,6 +68,27 @@ func TestMain(m *testing.M) {
|
|
|
os.Exit(0)
|
|
|
}
|
|
|
|
|
|
+// Tests that tailscaled starts up in TUN mode, and also without data races:
|
|
|
+// https://github.com/tailscale/tailscale/issues/7894
|
|
|
+func TestTUNMode(t *testing.T) {
|
|
|
+ if os.Getuid() != 0 {
|
|
|
+ t.Skip("skipping when not root")
|
|
|
+ }
|
|
|
+ t.Parallel()
|
|
|
+ env := newTestEnv(t)
|
|
|
+ env.tunMode = true
|
|
|
+ n1 := newTestNode(t, env)
|
|
|
+ d1 := n1.StartDaemon()
|
|
|
+
|
|
|
+ n1.AwaitResponding()
|
|
|
+ n1.MustUp()
|
|
|
+
|
|
|
+ t.Logf("Got IP: %v", n1.AwaitIP4())
|
|
|
+ n1.AwaitRunning()
|
|
|
+
|
|
|
+ d1.MustCleanShutdown(t)
|
|
|
+}
|
|
|
+
|
|
|
func TestOneNodeUpNoAuth(t *testing.T) {
|
|
|
t.Parallel()
|
|
|
env := newTestEnv(t)
|
|
|
@@ -808,9 +829,10 @@ func TestLogoutRemovesAllPeers(t *testing.T) {
|
|
|
// testEnv contains the test environment (set of servers) used by one
|
|
|
// or more nodes.
|
|
|
type testEnv struct {
|
|
|
- t testing.TB
|
|
|
- cli string
|
|
|
- daemon string
|
|
|
+ t testing.TB
|
|
|
+ tunMode bool
|
|
|
+ cli string
|
|
|
+ daemon string
|
|
|
|
|
|
LogCatcher *LogCatcher
|
|
|
LogCatcherServer *httptest.Server
|
|
|
@@ -899,12 +921,25 @@ func newTestNode(t *testing.T, env *testEnv) *testNode {
|
|
|
sockFile = filepath.Join(os.TempDir(), rands.HexString(8)+".sock")
|
|
|
t.Cleanup(func() { os.Remove(sockFile) })
|
|
|
}
|
|
|
- return &testNode{
|
|
|
+ n := &testNode{
|
|
|
env: env,
|
|
|
dir: dir,
|
|
|
sockFile: sockFile,
|
|
|
stateFile: filepath.Join(dir, "tailscale.state"),
|
|
|
}
|
|
|
+
|
|
|
+ // Look for a data race. Once we see the start marker, start logging the rest.
|
|
|
+ var sawRace bool
|
|
|
+ n.addLogLineHook(func(line []byte) {
|
|
|
+ if mem.Contains(mem.B(line), mem.S("WARNING: DATA RACE")) {
|
|
|
+ sawRace = true
|
|
|
+ }
|
|
|
+ if sawRace {
|
|
|
+ t.Logf("%s", line)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ return n
|
|
|
}
|
|
|
|
|
|
func (n *testNode) diskPrefs() *ipn.Prefs {
|
|
|
@@ -963,7 +998,7 @@ func (n *testNode) socks5AddrChan() <-chan string {
|
|
|
if i == -1 {
|
|
|
return
|
|
|
}
|
|
|
- addr := string(line)[i+len(sub):]
|
|
|
+ addr := strings.TrimSpace(string(line)[i+len(sub):])
|
|
|
select {
|
|
|
case ch <- addr:
|
|
|
default:
|
|
|
@@ -1010,11 +1045,10 @@ func (op *nodeOutputParser) parseLines() {
|
|
|
}
|
|
|
line := buf[:nl+1]
|
|
|
buf = buf[nl+1:]
|
|
|
- lineTrim := bytes.TrimSpace(line)
|
|
|
|
|
|
n.mu.Lock()
|
|
|
for _, f := range n.onLogLine {
|
|
|
- f(lineTrim)
|
|
|
+ f(line)
|
|
|
}
|
|
|
n.mu.Unlock()
|
|
|
}
|
|
|
@@ -1048,8 +1082,8 @@ func (n *testNode) StartDaemon() *Daemon {
|
|
|
|
|
|
func (n *testNode) StartDaemonAsIPNGOOS(ipnGOOS string) *Daemon {
|
|
|
t := n.env.t
|
|
|
- cmd := exec.Command(n.env.daemon,
|
|
|
- "--tun=userspace-networking",
|
|
|
+ cmd := exec.Command(n.env.daemon)
|
|
|
+ cmd.Args = append(cmd.Args,
|
|
|
"--state="+n.stateFile,
|
|
|
"--socket="+n.sockFile,
|
|
|
"--socks5-server=localhost:0",
|
|
|
@@ -1057,6 +1091,11 @@ func (n *testNode) StartDaemonAsIPNGOOS(ipnGOOS string) *Daemon {
|
|
|
if *verboseTailscaled {
|
|
|
cmd.Args = append(cmd.Args, "-verbose=2")
|
|
|
}
|
|
|
+ if !n.env.tunMode {
|
|
|
+ cmd.Args = append(cmd.Args,
|
|
|
+ "--tun=userspace-networking",
|
|
|
+ )
|
|
|
+ }
|
|
|
cmd.Env = append(os.Environ(),
|
|
|
"TS_DEBUG_PERMIT_HTTP_C2N=1",
|
|
|
"TS_LOG_TARGET="+n.env.LogCatcherServer.URL,
|
|
|
@@ -1067,10 +1106,7 @@ func (n *testNode) StartDaemonAsIPNGOOS(ipnGOOS string) *Daemon {
|
|
|
"TS_NETCHECK_GENERATE_204_URL="+n.env.ControlServer.URL+"/generate_204",
|
|
|
)
|
|
|
if version.IsRace() {
|
|
|
- const knownBroken = true // TODO(bradfitz,maisem): enable this once we fix all the races :(
|
|
|
- if !knownBroken {
|
|
|
- cmd.Env = append(cmd.Env, "GORACE=halt_on_error=1")
|
|
|
- }
|
|
|
+ cmd.Env = append(cmd.Env, "GORACE=halt_on_error=1")
|
|
|
}
|
|
|
cmd.Stderr = &nodeOutputParser{n: n}
|
|
|
if *verboseTailscaled {
|
|
|
@@ -1143,11 +1179,10 @@ func (n *testNode) AwaitListening() {
|
|
|
s := safesocket.DefaultConnectionStrategy(n.sockFile)
|
|
|
if err := tstest.WaitFor(20*time.Second, func() (err error) {
|
|
|
c, err := safesocket.Connect(s)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
+ if err == nil {
|
|
|
+ c.Close()
|
|
|
}
|
|
|
- c.Close()
|
|
|
- return nil
|
|
|
+ return err
|
|
|
}); err != nil {
|
|
|
t.Fatal(err)
|
|
|
}
|
|
|
@@ -1241,7 +1276,8 @@ func (n *testNode) AwaitNeedsLogin() {
|
|
|
// Tailscale returns a command that runs the tailscale CLI with the provided arguments.
|
|
|
// It does not start the process.
|
|
|
func (n *testNode) Tailscale(arg ...string) *exec.Cmd {
|
|
|
- cmd := exec.Command(n.env.cli, "--socket="+n.sockFile)
|
|
|
+ cmd := exec.Command(n.env.cli)
|
|
|
+ cmd.Args = append(cmd.Args, "--socket="+n.sockFile)
|
|
|
cmd.Args = append(cmd.Args, arg...)
|
|
|
cmd.Dir = n.dir
|
|
|
cmd.Env = append(os.Environ(),
|