Repository: go
Issue: x/crypto/ssh: listening on remote address blocks indefinitely when address doesn't contain a host part
Labels: NeedsInvestigation

<!-- Please answer these questions before submitting your issue. Thanks! -->

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.11.2 linux/amd64
</pre>

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/kanobe/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/kanobe/src/go"
GOPROXY=""
GORACE=""
GOROOT="/home/kanobe/download/go"
GOTMPDIR=""
GOTOOLDIR="/home/kanobe/download/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build496899549=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?

<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
-->

Created an SSH connection using ssh.Dial, and opened a Listener to listen on a port without specifying a host address. Then connected to that port (i.e. using telnet). 

This program demonstrates the issue:

<pre>
package main

import (
  "io/ioutil"
  "log"
  "os"
  "path"

  "golang.org/x/crypto/ssh"
)

func buildSshConfig(user, keyfile string) (conf *ssh.ClientConfig) {
  key, err := ioutil.ReadFile(keyfile)
  if err != nil {
    log.Fatal("unable to build ssh config: ", err)
  }

  signer, err := ssh.ParsePrivateKey(key)
  if err != nil {
    log.Fatal("unable to build ssh config: ", err)
  }

  conf = &ssh.ClientConfig{
    User: user,
    Auth: []ssh.AuthMethod{
      // Use the PublicKeys method for remote authentication.
      ssh.PublicKeys(signer),
    },
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
  }

  return
}

func main() {
  config := buildSshConfig(os.Getenv("USER"),
    path.Join(os.Getenv("HOME"), ".ssh/id_rsa"))

  conn, err := ssh.Dial("tcp", "localhost:22", config)
  if err != nil {
    log.Fatal("unable to connect: ", err)
  }
  defer conn.Close()

  // Request the remote side to open port 8080
  l, err := conn.Listen("tcp", ":8080")
  if err != nil {
    log.Fatal("unable to register tcp forward: ", err)
  }
  defer l.Close()

  log.Println("Calling Accept")
  l.Accept()
  log.Println("Accept returned")

}
</pre>



### What did you expect to see?

<pre>
Calling Accept
Accept Returned
</pre>

### What did you see instead?

<pre>
Calling Accept
</pre>

### Additional Info

It seems that if the local address is not specified in ssh.Client.Listen, the Accept call blocks indefinitely. For example this line fails in the above program:

<pre>
  l, err := conn.Listen("tcp", ":8080")
</pre>

But when changed to this it succeeds:

<pre>
  l, err := conn.Listen("tcp", "127.0.0.1:8080")
</pre>

The host may be omitted in net.Listen, so there is precedent for using no host. From net.Listen: "For TCP networks, if the host in the address parameter is empty or a literal unspecified IP address, Listen listens on all available unicast and anycast IP addresses of the local system." 

I think at a minimum if host may not be omitted, the documentation should mention that it is not supported, and the Listen call should return an error.