diff options
Diffstat (limited to 'libgo/go/net/ipsock_posix.go')
-rw-r--r-- | libgo/go/net/ipsock_posix.go | 129 |
1 files changed, 58 insertions, 71 deletions
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go index 05bf93956bf..4b4363a47a1 100644 --- a/libgo/go/net/ipsock_posix.go +++ b/libgo/go/net/ipsock_posix.go @@ -8,35 +8,29 @@ package net import ( "context" + "internal/poll" "runtime" "syscall" ) -func probeIPv4Stack() bool { +// Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication +// capabilities which are controlled by the IPV6_V6ONLY socket option +// and kernel configuration. +// +// Should we try to use the IPv4 socket interface if we're only +// dealing with IPv4 sockets? As long as the host system understands +// IPv4-mapped IPv6, it's okay to pass IPv4-mapeed IPv6 addresses to +// the IPv6 interface. That simplifies our code and is most +// general. Unfortunately, we need to run on kernels built without +// IPv6 support too. So probe the kernel to figure it out. +func (p *ipStackCapabilities) probe() { s, err := socketFunc(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) switch err { case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT: - return false case nil: - closeFunc(s) + poll.CloseFunc(s) + p.ipv4Enabled = true } - return true -} - -// Should we try to use the IPv4 socket interface if we're -// only dealing with IPv4 sockets? As long as the host system -// understands IPv6, it's okay to pass IPv4 addresses to the IPv6 -// interface. That simplifies our code and is most general. -// Unfortunately, we need to run on kernels built without IPv6 -// support too. So probe the kernel to figure it out. -// -// probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4- -// mapping capability which is controlled by IPV6_V6ONLY socket -// option and/or kernel state "net.inet6.ip6.v6only". -// It returns two boolean values. If the first boolean value is -// true, kernel supports basic IPv6 functionality. If the second -// boolean value is true, kernel supports IPv6 IPv4-mapping. -func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { var probes = []struct { laddr TCPAddr value int @@ -46,29 +40,19 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { // IPv4-mapped IPv6 address communication capability {laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0}, } - var supps [2]bool switch runtime.GOOS { case "dragonfly", "openbsd": - // Some released versions of DragonFly BSD pretend to - // accept IPV6_V6ONLY=0 successfully, but the state - // still stays IPV6_V6ONLY=1. Eventually DragonFly BSD - // stops pretending, but the transition period would - // cause unpredictable behavior and we need to avoid - // it. - // - // OpenBSD also doesn't support IPV6_V6ONLY=0 but it - // never pretends to accept IPV6_V6OLY=0. It always - // returns an error and we don't need to probe the - // capability. + // The latest DragonFly BSD and OpenBSD kernels don't + // support IPV6_V6ONLY=0. They always return an error + // and we don't need to probe the capability. probes = probes[:1] } - for i := range probes { s, err := socketFunc(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) if err != nil { continue } - defer closeFunc(s) + defer poll.CloseFunc(s) syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value) sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6) if err != nil { @@ -77,51 +61,55 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { if err := syscall.Bind(s, sa); err != nil { continue } - supps[i] = true + if i == 0 { + p.ipv6Enabled = true + } else { + p.ipv4MappedIPv6Enabled = true + } } - - return supps[0], supps[1] } -// favoriteAddrFamily returns the appropriate address family to -// the given net, laddr, raddr and mode. At first it figures -// address family out from the net. If mode indicates "listen" -// and laddr is a wildcard, it assumes that the user wants to -// make a passive connection with a wildcard address family, both -// AF_INET and AF_INET6, and a wildcard address like following: +// favoriteAddrFamily returns the appropriate address family for the +// given network, laddr, raddr and mode. +// +// If mode indicates "listen" and laddr is a wildcard, we assume that +// the user wants to make a passive-open connection with a wildcard +// address family, both AF_INET and AF_INET6, and a wildcard address +// like the following: // -// 1. A wild-wild listen, "tcp" + "" -// If the platform supports both IPv6 and IPv6 IPv4-mapping -// capabilities, or does not support IPv4, we assume that -// the user wants to listen on both IPv4 and IPv6 wildcard -// addresses over an AF_INET6 socket with IPV6_V6ONLY=0. -// Otherwise we prefer an IPv4 wildcard address listen over -// an AF_INET socket. +// - A listen for a wildcard communication domain, "tcp" or +// "udp", with a wildcard address: If the platform supports +// both IPv6 and IPv4-mapped IPv6 communication capabilities, +// or does not support IPv4, we use a dual stack, AF_INET6 and +// IPV6_V6ONLY=0, wildcard address listen. The dual stack +// wildcard address listen may fall back to an IPv6-only, +// AF_INET6 and IPV6_V6ONLY=1, wildcard address listen. +// Otherwise we prefer an IPv4-only, AF_INET, wildcard address +// listen. // -// 2. A wild-ipv4wild listen, "tcp" + "0.0.0.0" -// Same as 1. +// - A listen for a wildcard communication domain, "tcp" or +// "udp", with an IPv4 wildcard address: same as above. // -// 3. A wild-ipv6wild listen, "tcp" + "[::]" -// Almost same as 1 but we prefer an IPv6 wildcard address -// listen over an AF_INET6 socket with IPV6_V6ONLY=0 when -// the platform supports IPv6 capability but not IPv6 IPv4- -// mapping capability. +// - A listen for a wildcard communication domain, "tcp" or +// "udp", with an IPv6 wildcard address: same as above. // -// 4. A ipv4-ipv4wild listen, "tcp4" + "" or "0.0.0.0" -// We use an IPv4 (AF_INET) wildcard address listen. +// - A listen for an IPv4 communication domain, "tcp4" or "udp4", +// with an IPv4 wildcard address: We use an IPv4-only, AF_INET, +// wildcard address listen. // -// 5. A ipv6-ipv6wild listen, "tcp6" + "" or "[::]" -// We use an IPv6 (AF_INET6, IPV6_V6ONLY=1) wildcard address -// listen. +// - A listen for an IPv6 communication domain, "tcp6" or "udp6", +// with an IPv6 wildcard address: We use an IPv6-only, AF_INET6 +// and IPV6_V6ONLY=1, wildcard address listen. // -// Otherwise guess: if the addresses are IPv4 then returns AF_INET, -// or else returns AF_INET6. It also returns a boolean value what +// Otherwise guess: If the addresses are IPv4 then returns AF_INET, +// or else returns AF_INET6. It also returns a boolean value what // designates IPV6_V6ONLY option. // -// Note that OpenBSD allows neither "net.inet6.ip6.v6only=1" change -// nor IPPROTO_IPV6 level IPV6_V6ONLY socket option setting. -func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) { - switch net[len(net)-1] { +// Note that the latest DragonFly BSD and OpenBSD kernels allow +// neither "net.inet6.ip6.v6only=1" change nor IPPROTO_IPV6 level +// IPV6_V6ONLY socket option setting. +func favoriteAddrFamily(network string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) { + switch network[len(network)-1] { case '4': return syscall.AF_INET, false case '6': @@ -129,7 +117,7 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family } if mode == "listen" && (laddr == nil || laddr.isWildcard()) { - if supportsIPv4map || !supportsIPv4 { + if supportsIPv4map() || !supportsIPv4() { return syscall.AF_INET6, false } if laddr == nil { @@ -145,7 +133,6 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family return syscall.AF_INET6, false } -// Internet sockets (TCP, UDP, IP) func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, sotype, proto int, mode string) (fd *netFD, err error) { if (runtime.GOOS == "windows" || runtime.GOOS == "openbsd" || runtime.GOOS == "nacl") && mode == "dial" && raddr.isWildcard() { raddr = raddr.toLocal(net) @@ -187,7 +174,7 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e if ip6 == nil { return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()} } - sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneToInt(zone))} + sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneCache.index(zone))} copy(sa.Addr[:], ip6) return sa, nil } |