Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net: Listen("tcp", "0.0.0.0:1234") binds to IPv6 addresses #48723

Closed
ncw opened this issue Oct 1, 2021 · 4 comments
Closed

net: Listen("tcp", "0.0.0.0:1234") binds to IPv6 addresses #48723

ncw opened this issue Oct 1, 2021 · 4 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@ncw
Copy link
Contributor

ncw commented Oct 1, 2021

What version of Go are you using (go version)?

go version go1.17.1 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/ncw/.cache/go-build"
GOENV="/home/ncw/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/ncw/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/ncw/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/go/go1.17"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/go/go1.17/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17.1"
GCCGO="/usr/bin/gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
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-build3014442064=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Run this program

package main

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/exec"
	"strings"
)

func main() {
	if len(os.Args) != 2 {
		log.Fatalf("Syntax: %s bind_address", os.Args[0])
	}
	bindAddr := os.Args[1]
	go func() {
		_, err := net.Listen("tcp", bindAddr)
		if err != nil {
			log.Fatalf("net.Listen failed: %v", err)
		}
	}()
	// Read netstat
	cmd := exec.Command("netstat", "-tuanp")
	out, err := cmd.Output()
	if err != nil {
		log.Fatal(err)
	}
	// Print netstat lines with our PID in
	pid := fmt.Sprint(os.Getpid())
	for _, line := range strings.Split(string(out), "\n") {
		if strings.Contains(line, pid) {
			fmt.Println(line)
		}
	}
}

I get this

$ ./listen-bug 127.0.0.1:1234
tcp        0      0 127.0.0.1:1234          0.0.0.0:*               LISTEN      3179765/./listen-bu 
$ ./listen-bug 0.0.0.0:1234
tcp6       0      0 :::1234                 :::*                    LISTEN      3179773/./listen-bu 

Note the second of these is listening on IPv6 even though we explictly gave it an IPv4 bind address.

What did you expect to see?

I expected to see it not binding to IPv6 addresses, something like this

$ ./listen-bug 0.0.0.0:1234
tcp        0      0 0.0.0.0:1234          0.0.0.0:*               LISTEN      3179765/./listen-bu 

What did you see instead?

I see it binding to IPv4 and IPv6 addresses

$ ./listen-bug 0.0.0.0:1234
tcp6       0      0 :::1234                 :::*                    LISTEN      3179773/./listen-bu 

This was originally discussed in the rclone forum

@AlexanderYastrebov
Copy link
Contributor

https://pkg.go.dev/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. To only use IPv4, use network "tcp4".

@mknyszek mknyszek added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Oct 4, 2021
@mknyszek mknyszek added this to the Backlog milestone Oct 4, 2021
@mknyszek
Copy link
Contributor

mknyszek commented Oct 4, 2021

As @AlexanderYastrebov points out, this appears to be working as intended. Closing optimistically. Reply if you disagree or some new information arises.

CC @neild

@mknyszek mknyszek closed this as completed Oct 4, 2021
@ncw
Copy link
Contributor Author

ncw commented Oct 8, 2021

@mknyszek wrote:

Reply if you disagree or some new information arises.

I don't agree this is correct.

For example, apache uses this syntax to bind to only IPv4 addresses

https://httpd.apache.org/docs/2.4/bind.html#ipv6

If you want httpd to handle IPv4 connections only, regardless of what your platform and APR will support, specify an IPv4 address on all Listen directives, as in the following examples:

Listen 0.0.0.0:80
Listen 192.0.2.1:80

I would expect the go std lib to work the same way, not bind to IPv6 addresses when given a very obviously IPv4 address.

@mknyszek
Copy link
Contributor

mknyszek commented Oct 8, 2021

To be clear, because of the Go 1 backwards compatibility guarantee, this cannot be changed at this point without breaking somebody. It appears to be documented, and is otherwise working as per the documentation states. I'm not sure it's possible to move forward here.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

4 participants