github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/internal/nettest/interface.go (about)

     1  // 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  
     5  package nettest
     6  
     7  import "net"
     8  
     9  // IsMulticastCapable reports whether ifi is an IP multicast-capable
    10  // network interface. Network must be "ip", "ip4" or "ip6".
    11  func 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".
    27  func 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  
    49  func 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  
    69  func 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  }