[ssh] Compute protocol from input address

Local testing fails because the given input address for a Fuchsia device
(ipv6) returns "udp" as its `Network()`.  The ssh handshake hangs forever
when this protocol used.  We'll stick with tcp and tcp6 for now and expect
that all input address are ipv4 and ipv6 addresses.

Change-Id: I42b7ebd3b98aa669654901fe5869a9f5efb20021
diff --git a/botanist/ssh.go b/botanist/ssh.go
index ae41c26..2fc1a20 100644
--- a/botanist/ssh.go
+++ b/botanist/ssh.go
@@ -49,17 +49,44 @@
 }
 
 func ConnectSSH(ctx context.Context, address net.Addr, config *ssh.ClientConfig) (*ssh.Client, error) {
+	network, err := network(address)
+	if err != nil {
+		return nil, err
+	}
+
 	var client *ssh.Client
 
 	// TODO: figure out optimal backoff time and number of retries
-	err := retry.Retry(ctx, retry.WithMaxRetries(retry.NewConstantBackoff(time.Second), 10), func() error {
+	if err := retry.Retry(ctx, retry.WithMaxRetries(retry.NewConstantBackoff(time.Second), 10), func() error {
 		var err error
-		client, err = ssh.Dial(address.Network(), address.String(), config)
+		client, err = ssh.Dial(network, address.String(), config)
 		return err
-	}, nil)
-	if err != nil {
+	}, nil); err != nil {
 		return nil, fmt.Errorf("cannot connect to address '%s': %v", address, err)
 	}
 
 	return client, nil
 }
+
+// Returns the network to use to SSH into a device.
+func network(address net.Addr) (string, error) {
+	var ip *net.IP
+
+	// We need these type assertions because the net package (annoyingly) doesn't provide
+	// an interface for objects that have an IP address.
+	if udp, ok := address.(*net.UDPAddr); ok {
+		ip = &udp.IP
+	} else if tcp, ok := address.(*net.TCPAddr); ok {
+		ip = &tcp.IP
+	} else {
+		return "", fmt.Errorf("unsupported address type: %T", address)
+	}
+
+	if ip.To4() != nil {
+		return "tcp", nil // IPv4
+	}
+	if ip.To16() != nil {
+		return "tcp6", nil // IPv6
+	}
+	return "", fmt.Errorf("cannot infer network for IP address %s", ip.String())
+}
diff --git a/go.sum b/go.sum
index 2c3692e..cf60340 100644
--- a/go.sum
+++ b/go.sum
@@ -9,7 +9,6 @@
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57 h1:eqyIo2HjKhKe/mJzTG8n4VqvLXIOEG+SLdDqX7xGtkY=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/subcommands v0.0.0-20181012225330-46f0354f6315 h1:WW91Hq2v0qDzoPME+TPD4En72+d2Ue3ZMKPYfwR9yBU=
 github.com/google/subcommands v0.0.0-20181012225330-46f0354f6315/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
@@ -17,7 +16,6 @@
 github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
 github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -29,7 +27,6 @@
 go.chromium.org/luci v0.0.0-20181218015242-20acb618582d h1:WWlp6PQtC8FyaxytRO5UBYFBDcPOYy6+o7JmcvgLMuU=
 go.chromium.org/luci v0.0.0-20181218015242-20acb618582d/go.mod h1:MIQewVTLvOvc0UioV0JNqTNO/RspKFS0XEeoKrOxsdM=
 go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
-golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045 h1:Pn8fQdvx+z1avAi7fdM2kRYWQNxGlavNDSyzrQg2SsU=
 golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=