| // 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 |
| } |