blob: f0c575a7db847dabb4ddca3e68b96c5d6753812b [file] [log] [blame]
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -04001// 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
Joel Sing9ca57a72011-12-21 21:44:47 +11005// +build darwin freebsd linux netbsd openbsd windows
Russ Cox27159562011-09-15 16:48:57 -04006
Mikio Harae8cf49f2012-11-27 00:45:42 +09007// Internet protocol family sockets for POSIX
8
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -04009package net
10
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -060011import (
12 "syscall"
13 "time"
14)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040015
Mikio Haraf0291a82013-08-03 12:17:01 +090016func probeIPv4Stack() bool {
17 s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
18 switch err {
19 case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
20 return false
21 case nil:
22 closesocket(s)
23 }
24 return true
25}
26
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040027// Should we try to use the IPv4 socket interface if we're
28// only dealing with IPv4 sockets? As long as the host system
29// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
30// interface. That simplifies our code and is most general.
31// Unfortunately, we need to run on kernels built without IPv6
32// support too. So probe the kernel to figure it out.
33//
34// probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4-
35// mapping capability which is controlled by IPV6_V6ONLY socket
36// option and/or kernel state "net.inet6.ip6.v6only".
37// It returns two boolean values. If the first boolean value is
38// true, kernel supports basic IPv6 functionality. If the second
39// boolean value is true, kernel supports IPv6 IPv4-mapping.
40func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
41 var probes = []struct {
Mikio Harac0a4ce52013-07-25 19:29:20 +090042 laddr TCPAddr
43 ok bool
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040044 }{
45 // IPv6 communication capability
46 {TCPAddr{IP: ParseIP("::1")}, false},
47 // IPv6 IPv4-mapped address communication capability
48 {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
49 }
50
51 for i := range probes {
Russ Coxc017a822011-11-13 22:44:52 -050052 s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
53 if err != nil {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040054 continue
55 }
56 defer closesocket(s)
Mikio Harab5dc8722012-03-06 00:13:10 +090057 syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
Mikio Harac0a4ce52013-07-25 19:29:20 +090058 sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040059 if err != nil {
60 continue
61 }
Mikio Harac0a4ce52013-07-25 19:29:20 +090062 if err := syscall.Bind(s, sa); err != nil {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040063 continue
64 }
65 probes[i].ok = true
66 }
67
68 return probes[0].ok, probes[1].ok
69}
70
71// favoriteAddrFamily returns the appropriate address family to
Mikio Hara6fbe8052012-02-15 01:59:18 +090072// the given net, laddr, raddr and mode. At first it figures
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -040073// address family out from the net. If mode indicates "listen"
Mikio Harab5dc8722012-03-06 00:13:10 +090074// and laddr is a wildcard, it assumes that the user wants to
75// make a passive connection with a wildcard address family, both
76// AF_INET and AF_INET6, and a wildcard address like following:
77//
78// 1. A wild-wild listen, "tcp" + ""
79// If the platform supports both IPv6 and IPv6 IPv4-mapping
80// capabilities, we assume that the user want to listen on
81// both IPv4 and IPv6 wildcard address over an AF_INET6
82// socket with IPV6_V6ONLY=0. Otherwise we prefer an IPv4
83// wildcard address listen over an AF_INET socket.
84//
85// 2. A wild-ipv4wild listen, "tcp" + "0.0.0.0"
86// Same as 1.
87//
88// 3. A wild-ipv6wild listen, "tcp" + "[::]"
89// Almost same as 1 but we prefer an IPv6 wildcard address
90// listen over an AF_INET6 socket with IPV6_V6ONLY=0 when
91// the platform supports IPv6 capability but not IPv6 IPv4-
92// mapping capability.
93//
94// 4. A ipv4-ipv4wild listen, "tcp4" + "" or "0.0.0.0"
95// We use an IPv4 (AF_INET) wildcard address listen.
96//
97// 5. A ipv6-ipv6wild listen, "tcp6" + "" or "[::]"
98// We use an IPv6 (AF_INET6, IPV6_V6ONLY=1) wildcard address
99// listen.
100//
101// Otherwise guess: if the addresses are IPv4 then returns AF_INET,
102// or else returns AF_INET6. It also returns a boolean value what
103// designates IPV6_V6ONLY option.
104//
105// Note that OpenBSD allows neither "net.inet6.ip6.v6only=1" change
106// nor IPPROTO_IPV6 level IPV6_V6ONLY socket option setting.
107func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400108 switch net[len(net)-1] {
109 case '4':
Mikio Harab5dc8722012-03-06 00:13:10 +0900110 return syscall.AF_INET, false
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400111 case '6':
Mikio Harab5dc8722012-03-06 00:13:10 +0900112 return syscall.AF_INET6, true
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400113 }
114
Mikio Harab252fe72012-04-25 12:29:14 +0900115 if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
Mikio Harab5dc8722012-03-06 00:13:10 +0900116 if supportsIPv4map {
117 return syscall.AF_INET6, false
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400118 }
Mikio Harab252fe72012-04-25 12:29:14 +0900119 if laddr == nil {
120 return syscall.AF_INET, false
121 }
Mikio Harab5dc8722012-03-06 00:13:10 +0900122 return laddr.family(), false
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400123 }
124
125 if (laddr == nil || laddr.family() == syscall.AF_INET) &&
126 (raddr == nil || raddr.family() == syscall.AF_INET) {
Mikio Harab5dc8722012-03-06 00:13:10 +0900127 return syscall.AF_INET, false
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400128 }
Mikio Harab5dc8722012-03-06 00:13:10 +0900129 return syscall.AF_INET6, false
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400130}
131
Mikio Harab5dc8722012-03-06 00:13:10 +0900132// Internet sockets (TCP, UDP, IP)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400133
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600134func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400135 var la, ra syscall.Sockaddr
Mikio Harab5dc8722012-03-06 00:13:10 +0900136 family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400137 if laddr != nil {
Mikio Hara215777b2012-02-22 19:08:19 +0900138 if la, err = laddr.sockaddr(family); err != nil {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400139 goto Error
140 }
141 }
142 if raddr != nil {
Mikio Hara215777b2012-02-22 19:08:19 +0900143 if ra, err = raddr.sockaddr(family); err != nil {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400144 goto Error
145 }
146 }
Brad Fitzpatrickef6806f2012-11-08 10:35:16 -0600147 fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, deadline, toAddr)
Mikio Hara215777b2012-02-22 19:08:19 +0900148 if err != nil {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400149 goto Error
150 }
151 return fd, nil
152
153Error:
154 addr := raddr
155 if mode == "listen" {
156 addr = laddr
157 }
Mikio Hara215777b2012-02-22 19:08:19 +0900158 return nil, &OpError{mode, net, addr, err}
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400159}
160
Mikio Harae8cf49f2012-11-27 00:45:42 +0900161func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400162 switch family {
163 case syscall.AF_INET:
164 if len(ip) == 0 {
165 ip = IPv4zero
166 }
167 if ip = ip.To4(); ip == nil {
168 return nil, InvalidAddrError("non-IPv4 address")
169 }
Mikio Harae8cf49f2012-11-27 00:45:42 +0900170 sa := new(syscall.SockaddrInet4)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400171 for i := 0; i < IPv4len; i++ {
Mikio Harae8cf49f2012-11-27 00:45:42 +0900172 sa.Addr[i] = ip[i]
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400173 }
Mikio Harae8cf49f2012-11-27 00:45:42 +0900174 sa.Port = port
175 return sa, nil
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400176 case syscall.AF_INET6:
177 if len(ip) == 0 {
178 ip = IPv6zero
179 }
180 // IPv4 callers use 0.0.0.0 to mean "announce on any available address".
181 // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
Mikio Harab5dc8722012-03-06 00:13:10 +0900182 // which it refuses to do. Rewrite to the IPv6 unspecified address.
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400183 if ip.Equal(IPv4zero) {
184 ip = IPv6zero
185 }
186 if ip = ip.To16(); ip == nil {
187 return nil, InvalidAddrError("non-IPv6 address")
188 }
Mikio Harae8cf49f2012-11-27 00:45:42 +0900189 sa := new(syscall.SockaddrInet6)
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400190 for i := 0; i < IPv6len; i++ {
Mikio Harae8cf49f2012-11-27 00:45:42 +0900191 sa.Addr[i] = ip[i]
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400192 }
Mikio Harae8cf49f2012-11-27 00:45:42 +0900193 sa.Port = port
194 sa.ZoneId = uint32(zoneToInt(zone))
195 return sa, nil
Fazlul Shahriar0f7bc922011-08-17 13:28:29 -0400196 }
197 return nil, InvalidAddrError("unexpected socket family")
198}