cmd/tailscale: make "tailscale ping" also resolve names without DNS

This lets "tailscale ping $NAME" work even if MagicDNS is off, letting you
ping a name that shows up in "tailscale status".

More user friendly.
pull/1190/head
Brad Fitzpatrick 4 years ago
parent 9541886856
commit 4306433d1c

@ -64,11 +64,50 @@ func runPing(ctx context.Context, args []string) error {
c, bc, ctx, cancel := connect(ctx) c, bc, ctx, cancel := connect(ctx)
defer cancel() defer cancel()
if len(args) != 1 { if len(args) != 1 || args[0] == "" {
return errors.New("usage: ping <hostname-or-IP>") return errors.New("usage: ping <hostname-or-IP>")
} }
hostOrIP := args[0]
var ip string var ip string
prc := make(chan *ipnstate.PingResult, 1)
stc := make(chan *ipnstate.Status, 1)
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
}
if n.Status != nil {
stc <- n.Status
}
})
go pump(ctx, bc, c)
hostOrIP := args[0]
// If the argument is an IP address, use it directly without any resolution.
if net.ParseIP(hostOrIP) != nil {
ip = hostOrIP
}
// Otherwise, try to resolve it first from the network peer list.
if ip == "" {
bc.RequestStatus()
select {
case st := <-stc:
for _, ps := range st.Peer {
if hostOrIP == dnsOrQuoteHostname(st, ps) || hostOrIP == ps.DNSName {
ip = ps.TailAddr
break
}
}
case <-ctx.Done():
return ctx.Err()
}
}
// Finally, use DNS.
if ip == "" {
var res net.Resolver var res net.Resolver
if addrs, err := res.LookupHost(ctx, hostOrIP); err != nil { if addrs, err := res.LookupHost(ctx, hostOrIP); err != nil {
return fmt.Errorf("error looking up IP of %q: %v", hostOrIP, err) return fmt.Errorf("error looking up IP of %q: %v", hostOrIP, err)
@ -77,21 +116,11 @@ func runPing(ctx context.Context, args []string) error {
} else { } else {
ip = addrs[0] ip = addrs[0]
} }
}
if pingArgs.verbose && ip != hostOrIP { if pingArgs.verbose && ip != hostOrIP {
log.Printf("lookup %q => %q", hostOrIP, ip) log.Printf("lookup %q => %q", hostOrIP, ip)
} }
ch := make(chan *ipnstate.PingResult, 1)
bc.SetNotifyCallback(func(n ipn.Notify) {
if n.ErrMessage != nil {
log.Fatal(*n.ErrMessage)
}
if pr := n.PingResult; pr != nil && pr.IP == ip {
ch <- pr
}
})
go pump(ctx, bc, c)
n := 0 n := 0
anyPong := false anyPong := false
for { for {
@ -101,7 +130,7 @@ 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 pr := <-ch: case pr := <-prc:
timer.Stop() timer.Stop()
if pr.Err != "" { if pr.Err != "" {
return errors.New(pr.Err) return errors.New(pr.Err)

Loading…
Cancel
Save