Source file src/vendor/golang.org/x/net/nettest/nettest.go
1
2
3
4
5
6 package nettest
7
8 import (
9 "errors"
10 "fmt"
11 "io/ioutil"
12 "net"
13 "os"
14 "os/exec"
15 "runtime"
16 "strconv"
17 "strings"
18 "sync"
19 "time"
20 )
21
22 var (
23 stackOnce sync.Once
24 ipv4Enabled bool
25 ipv6Enabled bool
26 rawSocketSess bool
27 aixTechLvl int
28
29 aLongTimeAgo = time.Unix(233431200, 0)
30 neverTimeout = time.Time{}
31
32 errNoAvailableInterface = errors.New("no available interface")
33 errNoAvailableAddress = errors.New("no available address")
34 )
35
36 func probeStack() {
37 if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
38 ln.Close()
39 ipv4Enabled = true
40 }
41 if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil {
42 ln.Close()
43 ipv6Enabled = true
44 }
45 rawSocketSess = supportsRawSocket()
46 if runtime.GOOS == "aix" {
47 out, err := exec.Command("oslevel", "-s").Output()
48 if err == nil {
49 aixTechLvl, _ = strconv.Atoi(string(out[5:7]))
50 }
51 }
52 }
53
54 func aixTechLevel() int {
55 stackOnce.Do(probeStack)
56 return aixTechLvl
57 }
58
59
60
61 func SupportsIPv4() bool {
62 stackOnce.Do(probeStack)
63 return ipv4Enabled
64 }
65
66
67
68 func SupportsIPv6() bool {
69 stackOnce.Do(probeStack)
70 return ipv6Enabled
71 }
72
73
74
75 func SupportsRawSocket() bool {
76 stackOnce.Do(probeStack)
77 return rawSocketSess
78 }
79
80
81
82
83
84 func TestableNetwork(network string) bool {
85 ss := strings.Split(network, ":")
86 switch ss[0] {
87 case "ip+nopriv":
88
89
90 switch runtime.GOOS {
91 case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
92 return false
93 case "darwin":
94
95 if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
96 return false
97 }
98 }
99 case "ip", "ip4", "ip6":
100 switch runtime.GOOS {
101 case "fuchsia", "hurd", "js", "nacl", "plan9":
102 return false
103 default:
104 if os.Getuid() != 0 {
105 return false
106 }
107 }
108 case "unix", "unixgram":
109 switch runtime.GOOS {
110 case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
111 return false
112 case "aix":
113
114
115 if aixTechLevel() < 2 {
116 return false
117 }
118 return true
119 case "darwin":
120
121 if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
122 return false
123 }
124 }
125 case "unixpacket":
126 switch runtime.GOOS {
127 case "aix", "android", "fuchsia", "hurd", "darwin", "js", "nacl", "plan9", "windows":
128 return false
129 case "netbsd":
130
131
132 if runtime.GOARCH == "386" {
133 return false
134 }
135 }
136 }
137 switch ss[0] {
138 case "tcp4", "udp4", "ip4":
139 return SupportsIPv4()
140 case "tcp6", "udp6", "ip6":
141 return SupportsIPv6()
142 }
143 return true
144 }
145
146
147
148 func TestableAddress(network, address string) bool {
149 switch ss := strings.Split(network, ":"); ss[0] {
150 case "unix", "unixgram", "unixpacket":
151
152 if address[0] == '@' && runtime.GOOS != "linux" {
153 return false
154 }
155 }
156 return true
157 }
158
159
160
161
162
163
164 func NewLocalListener(network string) (net.Listener, error) {
165 switch network {
166 case "tcp":
167 if SupportsIPv4() {
168 if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
169 return ln, nil
170 }
171 }
172 if SupportsIPv6() {
173 return net.Listen("tcp6", "[::1]:0")
174 }
175 case "tcp4":
176 if SupportsIPv4() {
177 return net.Listen("tcp4", "127.0.0.1:0")
178 }
179 case "tcp6":
180 if SupportsIPv6() {
181 return net.Listen("tcp6", "[::1]:0")
182 }
183 case "unix", "unixpacket":
184 path, err := LocalPath()
185 if err != nil {
186 return nil, err
187 }
188 return net.Listen(network, path)
189 }
190 return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
191 }
192
193
194
195
196
197 func NewLocalPacketListener(network string) (net.PacketConn, error) {
198 switch network {
199 case "udp":
200 if SupportsIPv4() {
201 if c, err := net.ListenPacket("udp4", "127.0.0.1:0"); err == nil {
202 return c, nil
203 }
204 }
205 if SupportsIPv6() {
206 return net.ListenPacket("udp6", "[::1]:0")
207 }
208 case "udp4":
209 if SupportsIPv4() {
210 return net.ListenPacket("udp4", "127.0.0.1:0")
211 }
212 case "udp6":
213 if SupportsIPv6() {
214 return net.ListenPacket("udp6", "[::1]:0")
215 }
216 case "unixgram":
217 path, err := LocalPath()
218 if err != nil {
219 return nil, err
220 }
221 return net.ListenPacket(network, path)
222 }
223 return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
224 }
225
226
227
228 func LocalPath() (string, error) {
229 f, err := ioutil.TempFile("", "go-nettest")
230 if err != nil {
231 return "", err
232 }
233 path := f.Name()
234 f.Close()
235 os.Remove(path)
236 return path, nil
237 }
238
239
240
241
242
243 func MulticastSource(network string, ifi *net.Interface) (net.IP, error) {
244 switch network {
245 case "ip", "ip4", "ip6":
246 default:
247 return nil, errNoAvailableAddress
248 }
249 if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
250 return nil, errNoAvailableAddress
251 }
252 ip, ok := hasRoutableIP(network, ifi)
253 if !ok {
254 return nil, errNoAvailableAddress
255 }
256 return ip, nil
257 }
258
259
260
261 func LoopbackInterface() (*net.Interface, error) {
262 ift, err := net.Interfaces()
263 if err != nil {
264 return nil, errNoAvailableInterface
265 }
266 for _, ifi := range ift {
267 if ifi.Flags&net.FlagLoopback != 0 && ifi.Flags&net.FlagUp != 0 {
268 return &ifi, nil
269 }
270 }
271 return nil, errNoAvailableInterface
272 }
273
274
275
276
277
278 func RoutedInterface(network string, flags net.Flags) (*net.Interface, error) {
279 switch network {
280 case "ip", "ip4", "ip6":
281 default:
282 return nil, errNoAvailableInterface
283 }
284 ift, err := net.Interfaces()
285 if err != nil {
286 return nil, errNoAvailableInterface
287 }
288 for _, ifi := range ift {
289 if ifi.Flags&flags != flags {
290 continue
291 }
292 if _, ok := hasRoutableIP(network, &ifi); !ok {
293 continue
294 }
295 return &ifi, nil
296 }
297 return nil, errNoAvailableInterface
298 }
299
300 func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) {
301 ifat, err := ifi.Addrs()
302 if err != nil {
303 return nil, false
304 }
305 for _, ifa := range ifat {
306 switch ifa := ifa.(type) {
307 case *net.IPAddr:
308 if ip, ok := routableIP(network, ifa.IP); ok {
309 return ip, true
310 }
311 case *net.IPNet:
312 if ip, ok := routableIP(network, ifa.IP); ok {
313 return ip, true
314 }
315 }
316 }
317 return nil, false
318 }
319
320 func routableIP(network string, ip net.IP) (net.IP, bool) {
321 if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() {
322 return nil, false
323 }
324 switch network {
325 case "ip4":
326 if ip := ip.To4(); ip != nil {
327 return ip, true
328 }
329 case "ip6":
330 if ip.IsLoopback() {
331 return nil, false
332 }
333 if ip := ip.To16(); ip != nil && ip.To4() == nil {
334 return ip, true
335 }
336 default:
337 if ip := ip.To4(); ip != nil {
338 return ip, true
339 }
340 if ip := ip.To16(); ip != nil {
341 return ip, true
342 }
343 }
344 return nil, false
345 }
346
View as plain text