cmd/tailscale: fail if tailscaled closes the IPN connection

I was going to write a test for this using the tstest/integration test
stuff, but the testcontrol implementation isn't quite there yet (it
always registers nodes and doesn't provide AuthURLs). So, manually
tested for now.

Fixes #1843

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2021-05-04 07:49:29 -07:00
parent 68fb51b833
commit 962bf74875
3 changed files with 18 additions and 7 deletions

View File

@ -8,8 +8,10 @@
import ( import (
"context" "context"
"errors"
"flag" "flag"
"fmt" "fmt"
"io"
"log" "log"
"net" "net"
"os" "os"
@ -169,21 +171,22 @@ func connect(ctx context.Context) (net.Conn, *ipn.BackendClient, context.Context
} }
// pump receives backend messages on conn and pushes them into bc. // pump receives backend messages on conn and pushes them into bc.
func pump(ctx context.Context, bc *ipn.BackendClient, conn net.Conn) { func pump(ctx context.Context, bc *ipn.BackendClient, conn net.Conn) error {
defer conn.Close() defer conn.Close()
for ctx.Err() == nil { for ctx.Err() == nil {
msg, err := ipn.ReadMsg(conn) msg, err := ipn.ReadMsg(conn)
if err != nil { if err != nil {
if ctx.Err() != nil { if ctx.Err() != nil {
return return ctx.Err()
} }
if !gotSignal.Get() { if errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed) {
log.Printf("ReadMsg: %v\n", err) return fmt.Errorf("%w (tailscaled stopped running?)", err)
} }
break return err
} }
bc.GotNotifyMsg(msg) bc.GotNotifyMsg(msg)
} }
return ctx.Err()
} }
func strSliceContains(ss []string, s string) bool { func strSliceContains(ss []string, s string) bool {

View File

@ -80,7 +80,8 @@ func runPing(ctx context.Context, args []string) error {
prc <- pr prc <- pr
} }
}) })
go pump(ctx, bc, c) pumpErr := make(chan error, 1)
go func() { pumpErr <- pump(ctx, bc, c) }()
hostOrIP := args[0] hostOrIP := args[0]
ip, err := tailscaleIPFromArg(ctx, hostOrIP) ip, err := tailscaleIPFromArg(ctx, hostOrIP)
@ -101,6 +102,8 @@ func runPing(ctx context.Context, args []string) error {
select { select {
case <-timer.C: case <-timer.C:
fmt.Printf("timeout waiting for ping reply\n") fmt.Printf("timeout waiting for ping reply\n")
case err := <-pumpErr:
return err
case pr := <-prc: case pr := <-prc:
timer.Stop() timer.Stop()
if pr.Err != "" { if pr.Err != "" {

View File

@ -344,7 +344,8 @@ func runUp(ctx context.Context, args []string) error {
startingOrRunning := make(chan bool, 1) // gets value once starting or running startingOrRunning := make(chan bool, 1) // gets value once starting or running
gotEngineUpdate := make(chan bool, 1) // gets value upon an engine update gotEngineUpdate := make(chan bool, 1) // gets value upon an engine update
go pump(pumpCtx, bc, c) pumpErr := make(chan error, 1)
go func() { pumpErr <- pump(pumpCtx, bc, c) }()
printed := !simpleUp printed := !simpleUp
var loginOnce sync.Once var loginOnce sync.Once
@ -404,6 +405,8 @@ func runUp(ctx context.Context, args []string) error {
case <-gotEngineUpdate: case <-gotEngineUpdate:
case <-pumpCtx.Done(): case <-pumpCtx.Done():
return pumpCtx.Err() return pumpCtx.Err()
case err := <-pumpErr:
return err
} }
// Special case: bare "tailscale up" means to just start // Special case: bare "tailscale up" means to just start
@ -456,6 +459,8 @@ func runUp(ctx context.Context, args []string) error {
default: default:
} }
return pumpCtx.Err() return pumpCtx.Err()
case err := <-pumpErr:
return err
} }
} }