I was writing a test where I wanted an HTTP server to listen on a random port and then connect to this port. I wrote:
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("foo")
})
listener, err := net.Listen("tcp", ":0")
fmt.Println(err)
httpServer := &http.Server{Handler: mux}
go httpServer.Serve(listener)
fmt.Println("http://" + listener.Addr().String())
r, err := http.Get("http://" + listener.Addr().String())
fmt.Println(r)
fmt.Println(err)
I meant to write net.Listen("tcp", "127.0.0.1:0")
but accidentally wrote net.Listen("tcp", ":0")
.
For "http://" + listener.Addr().String()
it prints:
http://[::]:1709
where as far as I understand the "bracket colon colon bracket" means "all interfaces".
To my surprise, the http.Get("http://[::]:1709")
works, it connects to the webserver and "foo" is printed.
How is "http://[::]:1709" a valid address?
At least on a Linux system, this results in a connection being made to localhost.
The address ::
is IN6ADDR_ANY
, typically used when listening to listen for connections to any IPv6 address on the system. It's analogous to INADDR_ANY
, also known as 0.0.0.0
in IPv4.
Occasionally someone attempts to use one of these addresses as the destination address for an outgoing connection. When this happens:
When making an outgoing connection to 0.0.0.0
, Linux actually connects from 127.0.0.1
to 127.0.0.1
.
Similarly, when making an outgoing connection to ::
, Linux actually connects from ::1
to ::1
. Here is an example, taken from one of my websites (which happens to be an IP address lookup tool):
[error@murloc ~]$ curl -k -H "Host: myip.addr.space" https://[::]:8443/
::1
For completeness, here is the IPv4 version:
[error@murloc ~]$ curl -k -H "Host: myip.addr.space" https://0.0.0.0:8443/
127.0.0.1
Note that this is OS-specific. You would have received an error on Windows.