From a08d97847672674849f36a58baae064cffc7f51c Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 13 Apr 2021 08:50:16 -0700 Subject: [PATCH] cmd/tailscale/cli: make push get peerapi base via localapi, not TSMP ping Signed-off-by: Brad Fitzpatrick --- cmd/tailscale/cli/push.go | 73 +++++++++++++++------------------------ 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/cmd/tailscale/cli/push.go b/cmd/tailscale/cli/push.go index 3f9579b87..1bcc3672b 100644 --- a/cmd/tailscale/cli/push.go +++ b/cmd/tailscale/cli/push.go @@ -13,7 +13,6 @@ import ( "io" "log" "mime" - "net" "net/http" "net/url" "os" @@ -23,9 +22,8 @@ import ( "github.com/peterbourgon/ff/v2/ffcli" "golang.org/x/time/rate" + "inet.af/netaddr" "tailscale.com/client/tailscale" - "tailscale.com/ipn" - "tailscale.com/ipn/ipnstate" ) var pushCmd = &ffcli.Command{ @@ -63,11 +61,15 @@ func runPush(ctx context.Context, args []string) error { return err } - peerAPIPort, err := discoverPeerAPIPort(ctx, ip) + peerAPIBase, lastSeen, err := discoverPeerAPIBase(ctx, ip) if err != nil { return err } + if !lastSeen.IsZero() && time.Since(lastSeen) > lastSeenOld { + fmt.Fprintf(os.Stderr, "# warning: %s last seen %v ago\n", hostOrIP, time.Since(lastSeen).Round(time.Minute)) + } + var fileContents io.Reader var name = pushArgs.name var contentLength int64 = -1 @@ -103,7 +105,7 @@ func runPush(ctx context.Context, args []string) error { } } - dstURL := "http://" + net.JoinHostPort(ip, fmt.Sprint(peerAPIPort)) + "/v0/put/" + url.PathEscape(name) + dstURL := peerAPIBase + "/v0/put/" + url.PathEscape(name) req, err := http.NewRequestWithContext(ctx, "PUT", dstURL, fileContents) if err != nil { return err @@ -124,51 +126,28 @@ func runPush(ctx context.Context, args []string) error { return errors.New(res.Status) } -func discoverPeerAPIPort(ctx context.Context, ip string) (port uint16, err error) { - c, bc, ctx, cancel := connect(ctx) - defer cancel() - - prc := make(chan *ipnstate.PingResult, 2) - bc.SetNotifyCallback(func(n ipn.Notify) { - if n.ErrMessage != nil { - log.Fatal(*n.ErrMessage) - } - if pr := n.PingResult; pr != nil && pr.IP == ip { - prc <- pr - } - }) - go pump(ctx, bc, c) - - ticker := time.NewTicker(time.Second) - defer ticker.Stop() - - discoPings := 0 - timer := time.NewTimer(10 * time.Second) - defer timer.Stop() - - sendPings := func() { - bc.Ping(ip, false) - bc.Ping(ip, true) +func discoverPeerAPIBase(ctx context.Context, ipStr string) (base string, lastSeen time.Time, err error) { + ip, err := netaddr.ParseIP(ipStr) + if err != nil { + return "", time.Time{}, err } - sendPings() - for { - select { - case <-ticker.C: - sendPings() - case <-timer.C: - return 0, fmt.Errorf("timeout contacting %v; it offline?", ip) - case pr := <-prc: - if p := pr.PeerAPIPort; p != 0 { - return p, nil + fts, err := tailscale.FileTargets(ctx) + if err != nil { + return "", time.Time{}, err + } + for _, ft := range fts { + n := ft.Node + for _, a := range n.Addresses { + if a.IP != ip { + continue } - discoPings++ - if discoPings == 3 { - return 0, fmt.Errorf("%v is online, but seems to be running an old Tailscale version", ip) + if n.LastSeen != nil { + lastSeen = *n.LastSeen } - case <-ctx.Done(): - return 0, ctx.Err() + return ft.PeerAPIURL, lastSeen, nil } } + return "", time.Time{}, errors.New("target seems to be running an old Tailscale version") } const maxSniff = 4 << 20 @@ -213,6 +192,8 @@ func (r *slowReader) Read(p []byte) (n int, err error) { return } +const lastSeenOld = 20 * time.Minute + func runPushTargets(ctx context.Context, args []string) error { if len(args) > 0 { return errors.New("invalid arguments with --targets") @@ -227,7 +208,7 @@ func runPushTargets(ctx context.Context, args []string) error { if n.LastSeen == nil { ago = "\tnode never seen" } else { - if d := time.Since(*n.LastSeen); d > 20*time.Minute { + if d := time.Since(*n.LastSeen); d > lastSeenOld { ago = fmt.Sprintf("\tlast seen %v ago", d.Round(time.Minute)) } }