blob: 8e6333afe1a4d78492c94cd3476ad5103bd35083 [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// Copyright 2012 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
5package nettest
6
7import "net"
8
9// IsMulticastCapable reports whether ifi is an IP multicast-capable
10// network interface. Network must be "ip", "ip4" or "ip6".
11func IsMulticastCapable(network string, ifi *net.Interface) (net.IP, bool) {
12 switch network {
13 case "ip", "ip4", "ip6":
14 default:
15 return nil, false
16 }
17 if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
18 return nil, false
19 }
20 return hasRoutableIP(network, ifi)
21}
22
23// RoutedInterface returns a network interface that can route IP
24// traffic and satisfies flags. It returns nil when an appropriate
25// network interface is not found. Network must be "ip", "ip4" or
26// "ip6".
27func RoutedInterface(network string, flags net.Flags) *net.Interface {
28 switch network {
29 case "ip", "ip4", "ip6":
30 default:
31 return nil
32 }
33 ift, err := net.Interfaces()
34 if err != nil {
35 return nil
36 }
37 for _, ifi := range ift {
38 if ifi.Flags&flags != flags {
39 continue
40 }
41 if _, ok := hasRoutableIP(network, &ifi); !ok {
42 continue
43 }
44 return &ifi
45 }
46 return nil
47}
48
49func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) {
50 ifat, err := ifi.Addrs()
51 if err != nil {
52 return nil, false
53 }
54 for _, ifa := range ifat {
55 switch ifa := ifa.(type) {
56 case *net.IPAddr:
57 if ip := routableIP(network, ifa.IP); ip != nil {
58 return ip, true
59 }
60 case *net.IPNet:
61 if ip := routableIP(network, ifa.IP); ip != nil {
62 return ip, true
63 }
64 }
65 }
66 return nil, false
67}
68
69func routableIP(network string, ip net.IP) net.IP {
70 if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() {
71 return nil
72 }
73 switch network {
74 case "ip4":
75 if ip := ip.To4(); ip != nil {
76 return ip
77 }
78 case "ip6":
79 if ip.IsLoopback() { // addressing scope of the loopback address depends on each implementation
80 return nil
81 }
82 if ip := ip.To16(); ip != nil && ip.To4() == nil {
83 return ip
84 }
85 default:
86 if ip := ip.To4(); ip != nil {
87 return ip
88 }
89 if ip := ip.To16(); ip != nil {
90 return ip
91 }
92 }
93 return nil
94}