|
|
@@ -0,0 +1,91 @@
|
|
|
+// Copyright 2012 The Go Authors. All rights reserved.
|
|
|
+// Use of this source code is governed by a BSD-style
|
|
|
+// license that can be found in the LICENSE file.
|
|
|
+
|
|
|
+package nettest
|
|
|
+
|
|
|
+import "net"
|
|
|
+
|
|
|
+// IsMulticastCapable reports whether ifi is an IP multicast-capable
|
|
|
+// network interface. Network must be "ip", "ip4" or "ip6".
|
|
|
+func IsMulticastCapable(network string, ifi *net.Interface) (net.IP, bool) {
|
|
|
+ switch network {
|
|
|
+ case "ip", "ip4", "ip6":
|
|
|
+ default:
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ return hasRoutableIP(network, ifi)
|
|
|
+}
|
|
|
+
|
|
|
+// RoutedInterface returns a network interface that can route IP
|
|
|
+// traffic and satisfies flags. It returns nil when an appropriate
|
|
|
+// network interface is not found. Network must be "ip", "ip4" or
|
|
|
+// "ip6".
|
|
|
+func RoutedInterface(network string, flags net.Flags) *net.Interface {
|
|
|
+ switch network {
|
|
|
+ case "ip", "ip4", "ip6":
|
|
|
+ default:
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ ift, err := net.Interfaces()
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ for _, ifi := range ift {
|
|
|
+ if ifi.Flags&flags != flags {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if _, ok := hasRoutableIP(network, &ifi); !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ return &ifi
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) {
|
|
|
+ ifat, err := ifi.Addrs()
|
|
|
+ if err != nil {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ for _, ifa := range ifat {
|
|
|
+ switch ifa := ifa.(type) {
|
|
|
+ case *net.IPAddr:
|
|
|
+ if ip := routableIP(network, ifa.IP); ip != nil {
|
|
|
+ return ip, true
|
|
|
+ }
|
|
|
+ case *net.IPNet:
|
|
|
+ if ip := routableIP(network, ifa.IP); ip != nil {
|
|
|
+ return ip, true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil, false
|
|
|
+}
|
|
|
+
|
|
|
+func routableIP(network string, ip net.IP) net.IP {
|
|
|
+ if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ switch network {
|
|
|
+ case "ip4":
|
|
|
+ if ip := ip.To4(); ip != nil {
|
|
|
+ return ip
|
|
|
+ }
|
|
|
+ case "ip6":
|
|
|
+ if ip := ip.To16(); ip != nil && ip.To4() == nil {
|
|
|
+ return ip
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ if ip := ip.To4(); ip != nil {
|
|
|
+ return ip
|
|
|
+ }
|
|
|
+ if ip := ip.To16(); ip != nil {
|
|
|
+ return ip
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|