Go binds the unspecified IPv6 address (::) to its IPv4 equivalent (0.0.0.0)
because of questionable software in the ecosystem and the fact that OpenBSD
does not support dual-family sockets;  (incomplete) history:

- https://github.com/golang/go/issues/18806
- https://go-review.googlesource.com/c/go/+/47554

So net.Listen("tcp", "[::]:1234") won't use IPv6 unless you use "tcp6".
Ports I use do not expose a knob for the address family ("network" in Go),
so using ":1234" or "[::]:1234" never uses IPv6 and specific IPv6 addresses
lack the catch-all semantic often required.

net.Dial() to connect to a remote socket has the same problem.
See the links above for why Go behaves that way.


I'd like to fix that such that configs like "[::]:1234" on OpenBSD allow me
to listen on all IPv6 addresses, like it should.

With multimedia/dms I ran into https://github.com/anacrolix/dms/pull/171,
where we made dms flip the network to "tcp6" in case of the unspecified
address to fix this, but that is an application hack for a runtime problem
on a niche OS and not viable.


Below is a test program (expects,  e.g. httpd(8) listening on *, 80/tcp)
demonstrating Dial() and Listen() across all networks and addresses:
- tcp,  :: now listens on :: instead of 0.0.0.0
- tcp4, :: now errors instead of connects to/listens on 127.0.0.1/0.0.0.0
- rest remains unchanged


Neither the patch, nor the final behaviour is perfect, but it fixes two
things while, seemingly, not breaking others.


Feedback?


$ netstat -na | grep -w 80
tcp          0      0  *.80                   *.*                    LISTEN
tcp6         0      0  *.80                   *.*                    LISTEN

$ cat test.go
package main

import (
        "fmt"
        "net"
)

func main() {
        fmt.Printf("%4s  %9s  %9s  %9s\n\n", "net", "addr", "Dial()", 
"Listen()")

        for _, n := range []string{"tcp", "tcp4", "tcp6"} {
                for _, a := range []string{"", "0.0.0.0", "127.0.0.1", "[::]", 
"[::1]", "localhost"} {
                        fmt.Printf("%4s  %9s", n, a)

                        d, dErr := net.Dial(n, a+":80")
                        if dErr == nil {
                                fmt.Printf("  %9s", 
d.RemoteAddr().(*net.TCPAddr).IP)
                                d.Close()
                        }

                        l, lErr := net.Listen(n, a+":")
                        if lErr == nil {
                                fmt.Printf("  %9s", l.Addr().(*net.TCPAddr).IP)
                                l.Close()
                        }

                        fmt.Printf("\n")
                        if dErr != nil {
                                fmt.Printf("%80s\n", dErr)
                        }
                        if lErr != nil {
                                fmt.Printf("%80s\n", lErr)
                        }
                }
        }
}

$ go run test.go | tee current
 net       addr     Dial()   Listen()

 tcp             127.0.0.1    0.0.0.0
 tcp    0.0.0.0  127.0.0.1    0.0.0.0
 tcp  127.0.0.1  127.0.0.1  127.0.0.1
 tcp       [::]  127.0.0.1    0.0.0.0
 tcp      [::1]        ::1        ::1
 tcp  localhost  127.0.0.1  127.0.0.1
tcp4             127.0.0.1    0.0.0.0
tcp4    0.0.0.0  127.0.0.1    0.0.0.0
tcp4  127.0.0.1  127.0.0.1  127.0.0.1
tcp4       [::]  127.0.0.1    0.0.0.0
tcp4      [::1]
                               dial tcp4: address ::1: no suitable address found
                             listen tcp4: address ::1: no suitable address found
tcp4  localhost  127.0.0.1  127.0.0.1
tcp6                   ::1         ::
tcp6    0.0.0.0
                           dial tcp6: address 0.0.0.0: no suitable address found
                         listen tcp6: address 0.0.0.0: no suitable address found
tcp6  127.0.0.1
                         dial tcp6: address 127.0.0.1: no suitable address found
                       listen tcp6: address 127.0.0.1: no suitable address found
tcp6       [::]        ::1         ::
tcp6      [::1]        ::1        ::1
tcp6  localhost        ::1        ::1


$ make update
[...]
go-1.27.1->1.27.1p0: ok


$ go run test.go | tee patch
 net       addr     Dial()   Listen()

 tcp             127.0.0.1    0.0.0.0
 tcp    0.0.0.0  127.0.0.1    0.0.0.0
 tcp  127.0.0.1  127.0.0.1  127.0.0.1
 tcp       [::]  127.0.0.1         ::
 tcp      [::1]        ::1        ::1
 tcp  localhost  127.0.0.1  127.0.0.1
tcp4             127.0.0.1    0.0.0.0
tcp4    0.0.0.0  127.0.0.1    0.0.0.0
tcp4  127.0.0.1  127.0.0.1  127.0.0.1
tcp4       [::]
                                dial tcp4: address ::: no suitable address found
                              listen tcp4: address ::: no suitable address found
tcp4      [::1]
                               dial tcp4: address ::1: no suitable address found
                             listen tcp4: address ::1: no suitable address found
tcp4  localhost  127.0.0.1  127.0.0.1
tcp6                   ::1         ::
tcp6    0.0.0.0
                           dial tcp6: address 0.0.0.0: no suitable address found
                         listen tcp6: address 0.0.0.0: no suitable address found
tcp6  127.0.0.1
                         dial tcp6: address 127.0.0.1: no suitable address found
                       listen tcp6: address 127.0.0.1: no suitable address found
tcp6       [::]        ::1         ::
tcp6      [::1]        ::1        ::1
tcp6  localhost        ::1        ::1



Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/go/Makefile,v
diff -u -p -r1.184 Makefile
--- Makefile    16 Sep 2026 16:16:51 -0000      1.184
+++ Makefile    20 Sep 2026 22:01:26 -0000
@@ -8,6 +8,7 @@ COMMENT =               Go programming language
 # increment _MODGO_SYSTEM_VERSION in go.port.mk after updating to a new
 # version, to trigger updates of go-compiled ports
 VERSION =              1.27.1
+REVISION =             0
 DISTNAME =             go${VERSION}.src
 PKGNAME =              go-${VERSION}
 PKGSPEC =              ${FULLPKGNAME:S/go-/go-=/}
Index: patches/patch-src_net_ipsock_go
===================================================================
RCS file: patches/patch-src_net_ipsock_go
diff -N patches/patch-src_net_ipsock_go
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_net_ipsock_go     20 Sep 2026 22:02:22 -0000
@@ -0,0 +1,19 @@
+cause :: to resolve to IPv6 sockets
+
+Index: src/net/ipsock.go
+--- src/net/ipsock.go.orig
++++ src/net/ipsock.go
+@@ -290,13 +290,6 @@ func (r *Resolver) internetAddrList(ctx context.Contex
+       if err != nil {
+               return nil, err
+       }
+-      // Issue 18806: if the machine has halfway configured
+-      // IPv6 such that it can bind on "::" (IPv6unspecified)
+-      // but not connect back to that same address, fall
+-      // back to dialing 0.0.0.0.
+-      if len(ips) == 1 && ips[0].IP.Equal(IPv6unspecified) {
+-              ips = append(ips, IPAddr{IP: IPv4zero})
+-      }
+ 
+       var filter func(IPAddr) bool
+       if net != "" && net[len(net)-1] == '4' {

Reply via email to