cmd/tailscale/cli: make push get peerapi base via localapi, not TSMP ping

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/1696/head
Brad Fitzpatrick 3 years ago
parent 1dc2cf4835
commit a08d978476

@ -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)
}
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
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
}
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))
}
}

Loading…
Cancel
Save