...

Source file src/net/ipsock_posix.go

Documentation: net

		 1  // Copyright 2009 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
		 6  // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
		 7  
		 8  package net
		 9  
		10  import (
		11  	"context"
		12  	"internal/poll"
		13  	"runtime"
		14  	"syscall"
		15  )
		16  
		17  // probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
		18  // capabilities which are controlled by the IPV6_V6ONLY socket option
		19  // and kernel configuration.
		20  //
		21  // Should we try to use the IPv4 socket interface if we're only
		22  // dealing with IPv4 sockets? As long as the host system understands
		23  // IPv4-mapped IPv6, it's okay to pass IPv4-mapped IPv6 addresses to
		24  // the IPv6 interface. That simplifies our code and is most
		25  // general. Unfortunately, we need to run on kernels built without
		26  // IPv6 support too. So probe the kernel to figure it out.
		27  func (p *ipStackCapabilities) probe() {
		28  	s, err := sysSocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
		29  	switch err {
		30  	case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
		31  	case nil:
		32  		poll.CloseFunc(s)
		33  		p.ipv4Enabled = true
		34  	}
		35  	var probes = []struct {
		36  		laddr TCPAddr
		37  		value int
		38  	}{
		39  		// IPv6 communication capability
		40  		{laddr: TCPAddr{IP: ParseIP("::1")}, value: 1},
		41  		// IPv4-mapped IPv6 address communication capability
		42  		{laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
		43  	}
		44  	switch runtime.GOOS {
		45  	case "dragonfly", "openbsd":
		46  		// The latest DragonFly BSD and OpenBSD kernels don't
		47  		// support IPV6_V6ONLY=0. They always return an error
		48  		// and we don't need to probe the capability.
		49  		probes = probes[:1]
		50  	}
		51  	for i := range probes {
		52  		s, err := sysSocket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
		53  		if err != nil {
		54  			continue
		55  		}
		56  		defer poll.CloseFunc(s)
		57  		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
		58  		sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
		59  		if err != nil {
		60  			continue
		61  		}
		62  		if err := syscall.Bind(s, sa); err != nil {
		63  			continue
		64  		}
		65  		if i == 0 {
		66  			p.ipv6Enabled = true
		67  		} else {
		68  			p.ipv4MappedIPv6Enabled = true
		69  		}
		70  	}
		71  }
		72  
		73  // favoriteAddrFamily returns the appropriate address family for the
		74  // given network, laddr, raddr and mode.
		75  //
		76  // If mode indicates "listen" and laddr is a wildcard, we assume that
		77  // the user wants to make a passive-open connection with a wildcard
		78  // address family, both AF_INET and AF_INET6, and a wildcard address
		79  // like the following:
		80  //
		81  //	- A listen for a wildcard communication domain, "tcp" or
		82  //		"udp", with a wildcard address: If the platform supports
		83  //		both IPv6 and IPv4-mapped IPv6 communication capabilities,
		84  //		or does not support IPv4, we use a dual stack, AF_INET6 and
		85  //		IPV6_V6ONLY=0, wildcard address listen. The dual stack
		86  //		wildcard address listen may fall back to an IPv6-only,
		87  //		AF_INET6 and IPV6_V6ONLY=1, wildcard address listen.
		88  //		Otherwise we prefer an IPv4-only, AF_INET, wildcard address
		89  //		listen.
		90  //
		91  //	- A listen for a wildcard communication domain, "tcp" or
		92  //		"udp", with an IPv4 wildcard address: same as above.
		93  //
		94  //	- A listen for a wildcard communication domain, "tcp" or
		95  //		"udp", with an IPv6 wildcard address: same as above.
		96  //
		97  //	- A listen for an IPv4 communication domain, "tcp4" or "udp4",
		98  //		with an IPv4 wildcard address: We use an IPv4-only, AF_INET,
		99  //		wildcard address listen.
	 100  //
	 101  //	- A listen for an IPv6 communication domain, "tcp6" or "udp6",
	 102  //		with an IPv6 wildcard address: We use an IPv6-only, AF_INET6
	 103  //		and IPV6_V6ONLY=1, wildcard address listen.
	 104  //
	 105  // Otherwise guess: If the addresses are IPv4 then returns AF_INET,
	 106  // or else returns AF_INET6. It also returns a boolean value what
	 107  // designates IPV6_V6ONLY option.
	 108  //
	 109  // Note that the latest DragonFly BSD and OpenBSD kernels allow
	 110  // neither "net.inet6.ip6.v6only=1" change nor IPPROTO_IPV6 level
	 111  // IPV6_V6ONLY socket option setting.
	 112  func favoriteAddrFamily(network string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
	 113  	switch network[len(network)-1] {
	 114  	case '4':
	 115  		return syscall.AF_INET, false
	 116  	case '6':
	 117  		return syscall.AF_INET6, true
	 118  	}
	 119  
	 120  	if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
	 121  		if supportsIPv4map() || !supportsIPv4() {
	 122  			return syscall.AF_INET6, false
	 123  		}
	 124  		if laddr == nil {
	 125  			return syscall.AF_INET, false
	 126  		}
	 127  		return laddr.family(), false
	 128  	}
	 129  
	 130  	if (laddr == nil || laddr.family() == syscall.AF_INET) &&
	 131  		(raddr == nil || raddr.family() == syscall.AF_INET) {
	 132  		return syscall.AF_INET, false
	 133  	}
	 134  	return syscall.AF_INET6, false
	 135  }
	 136  
	 137  func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, sotype, proto int, mode string, ctrlFn func(string, string, syscall.RawConn) error) (fd *netFD, err error) {
	 138  	if (runtime.GOOS == "aix" || runtime.GOOS == "windows" || runtime.GOOS == "openbsd") && mode == "dial" && raddr.isWildcard() {
	 139  		raddr = raddr.toLocal(net)
	 140  	}
	 141  	family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
	 142  	return socket(ctx, net, family, sotype, proto, ipv6only, laddr, raddr, ctrlFn)
	 143  }
	 144  
	 145  func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
	 146  	switch family {
	 147  	case syscall.AF_INET:
	 148  		if len(ip) == 0 {
	 149  			ip = IPv4zero
	 150  		}
	 151  		ip4 := ip.To4()
	 152  		if ip4 == nil {
	 153  			return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
	 154  		}
	 155  		sa := &syscall.SockaddrInet4{Port: port}
	 156  		copy(sa.Addr[:], ip4)
	 157  		return sa, nil
	 158  	case syscall.AF_INET6:
	 159  		// In general, an IP wildcard address, which is either
	 160  		// "0.0.0.0" or "::", means the entire IP addressing
	 161  		// space. For some historical reason, it is used to
	 162  		// specify "any available address" on some operations
	 163  		// of IP node.
	 164  		//
	 165  		// When the IP node supports IPv4-mapped IPv6 address,
	 166  		// we allow a listener to listen to the wildcard
	 167  		// address of both IP addressing spaces by specifying
	 168  		// IPv6 wildcard address.
	 169  		if len(ip) == 0 || ip.Equal(IPv4zero) {
	 170  			ip = IPv6zero
	 171  		}
	 172  		// We accept any IPv6 address including IPv4-mapped
	 173  		// IPv6 address.
	 174  		ip6 := ip.To16()
	 175  		if ip6 == nil {
	 176  			return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
	 177  		}
	 178  		sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneCache.index(zone))}
	 179  		copy(sa.Addr[:], ip6)
	 180  		return sa, nil
	 181  	}
	 182  	return nil, &AddrError{Err: "invalid address family", Addr: ip.String()}
	 183  }
	 184  

View as plain text