// 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.IsLoopback() { // addressing scope of the loopback address depends on each implementation return nil } 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 }