Run Format

Source file src/pkg/net/ipsock_posix.go

     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	// +build darwin freebsd linux netbsd openbsd windows
     6	
     7	// Internet protocol family sockets for POSIX
     8	
     9	package net
    10	
    11	import (
    12		"syscall"
    13		"time"
    14	)
    15	
    16	// Should we try to use the IPv4 socket interface if we're
    17	// only dealing with IPv4 sockets?  As long as the host system
    18	// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
    19	// interface.  That simplifies our code and is most general.
    20	// Unfortunately, we need to run on kernels built without IPv6
    21	// support too.  So probe the kernel to figure it out.
    22	//
    23	// probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4-
    24	// mapping capability which is controlled by IPV6_V6ONLY socket
    25	// option and/or kernel state "net.inet6.ip6.v6only".
    26	// It returns two boolean values.  If the first boolean value is
    27	// true, kernel supports basic IPv6 functionality.  If the second
    28	// boolean value is true, kernel supports IPv6 IPv4-mapping.
    29	func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
    30		var probes = []struct {
    31			la TCPAddr
    32			ok bool
    33		}{
    34			// IPv6 communication capability
    35			{TCPAddr{IP: ParseIP("::1")}, false},
    36			// IPv6 IPv4-mapped address communication capability
    37			{TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
    38		}
    39	
    40		for i := range probes {
    41			s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
    42			if err != nil {
    43				continue
    44			}
    45			defer closesocket(s)
    46			syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
    47			sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6)
    48			if err != nil {
    49				continue
    50			}
    51			err = syscall.Bind(s, sa)
    52			if err != nil {
    53				continue
    54			}
    55			probes[i].ok = true
    56		}
    57	
    58		return probes[0].ok, probes[1].ok
    59	}
    60	
    61	// favoriteAddrFamily returns the appropriate address family to
    62	// the given net, laddr, raddr and mode.  At first it figures
    63	// address family out from the net.  If mode indicates "listen"
    64	// and laddr is a wildcard, it assumes that the user wants to
    65	// make a passive connection with a wildcard address family, both
    66	// AF_INET and AF_INET6, and a wildcard address like following:
    67	//
    68	//	1. A wild-wild listen, "tcp" + ""
    69	//	If the platform supports both IPv6 and IPv6 IPv4-mapping
    70	//	capabilities, we assume that the user want to listen on
    71	//	both IPv4 and IPv6 wildcard address over an AF_INET6
    72	//	socket with IPV6_V6ONLY=0.  Otherwise we prefer an IPv4
    73	//	wildcard address listen over an AF_INET socket.
    74	//
    75	//	2. A wild-ipv4wild listen, "tcp" + "0.0.0.0"
    76	//	Same as 1.
    77	//
    78	//	3. A wild-ipv6wild listen, "tcp" + "[::]"
    79	//	Almost same as 1 but we prefer an IPv6 wildcard address
    80	//	listen over an AF_INET6 socket with IPV6_V6ONLY=0 when
    81	//	the platform supports IPv6 capability but not IPv6 IPv4-
    82	//	mapping capability.
    83	//
    84	//	4. A ipv4-ipv4wild listen, "tcp4" + "" or "0.0.0.0"
    85	//	We use an IPv4 (AF_INET) wildcard address listen.
    86	//
    87	//	5. A ipv6-ipv6wild listen, "tcp6" + "" or "[::]"
    88	//	We use an IPv6 (AF_INET6, IPV6_V6ONLY=1) wildcard address
    89	//	listen.
    90	//
    91	// Otherwise guess: if the addresses are IPv4 then returns AF_INET,
    92	// or else returns AF_INET6.  It also returns a boolean value what
    93	// designates IPV6_V6ONLY option.
    94	//
    95	// Note that OpenBSD allows neither "net.inet6.ip6.v6only=1" change
    96	// nor IPPROTO_IPV6 level IPV6_V6ONLY socket option setting.
    97	func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
    98		switch net[len(net)-1] {
    99		case '4':
   100			return syscall.AF_INET, false
   101		case '6':
   102			return syscall.AF_INET6, true
   103		}
   104	
   105		if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
   106			if supportsIPv4map {
   107				return syscall.AF_INET6, false
   108			}
   109			if laddr == nil {
   110				return syscall.AF_INET, false
   111			}
   112			return laddr.family(), false
   113		}
   114	
   115		if (laddr == nil || laddr.family() == syscall.AF_INET) &&
   116			(raddr == nil || raddr.family() == syscall.AF_INET) {
   117			return syscall.AF_INET, false
   118		}
   119		return syscall.AF_INET6, false
   120	}
   121	
   122	// Internet sockets (TCP, UDP, IP)
   123	
   124	// A sockaddr represents a TCP, UDP or IP network address that can
   125	// be converted into a syscall.Sockaddr.
   126	type sockaddr interface {
   127		Addr
   128		family() int
   129		isWildcard() bool
   130		sockaddr(family int) (syscall.Sockaddr, error)
   131	}
   132	
   133	func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
   134		var la, ra syscall.Sockaddr
   135		family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
   136		if laddr != nil {
   137			if la, err = laddr.sockaddr(family); err != nil {
   138				goto Error
   139			}
   140		}
   141		if raddr != nil {
   142			if ra, err = raddr.sockaddr(family); err != nil {
   143				goto Error
   144			}
   145		}
   146		fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, deadline, toAddr)
   147		if err != nil {
   148			goto Error
   149		}
   150		return fd, nil
   151	
   152	Error:
   153		addr := raddr
   154		if mode == "listen" {
   155			addr = laddr
   156		}
   157		return nil, &OpError{mode, net, addr, err}
   158	}
   159	
   160	func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
   161		switch family {
   162		case syscall.AF_INET:
   163			if len(ip) == 0 {
   164				ip = IPv4zero
   165			}
   166			if ip = ip.To4(); ip == nil {
   167				return nil, InvalidAddrError("non-IPv4 address")
   168			}
   169			sa := new(syscall.SockaddrInet4)
   170			for i := 0; i < IPv4len; i++ {
   171				sa.Addr[i] = ip[i]
   172			}
   173			sa.Port = port
   174			return sa, nil
   175		case syscall.AF_INET6:
   176			if len(ip) == 0 {
   177				ip = IPv6zero
   178			}
   179			// IPv4 callers use 0.0.0.0 to mean "announce on any available address".
   180			// In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
   181			// which it refuses to do.  Rewrite to the IPv6 unspecified address.
   182			if ip.Equal(IPv4zero) {
   183				ip = IPv6zero
   184			}
   185			if ip = ip.To16(); ip == nil {
   186				return nil, InvalidAddrError("non-IPv6 address")
   187			}
   188			sa := new(syscall.SockaddrInet6)
   189			for i := 0; i < IPv6len; i++ {
   190				sa.Addr[i] = ip[i]
   191			}
   192			sa.Port = port
   193			sa.ZoneId = uint32(zoneToInt(zone))
   194			return sa, nil
   195		}
   196		return nil, InvalidAddrError("unexpected socket family")
   197	}

View as plain text