github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/netutils/utils_linux.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  // Network utility functions.
     5  
     6  package netutils
     7  
     8  import (
     9  	"fmt"
    10  	"net"
    11  	"strings"
    12  
    13  	"github.com/docker/libnetwork/ipamutils"
    14  	"github.com/docker/libnetwork/ns"
    15  	"github.com/docker/libnetwork/osl"
    16  	"github.com/docker/libnetwork/resolvconf"
    17  	"github.com/docker/libnetwork/types"
    18  	"github.com/pkg/errors"
    19  	"github.com/vishvananda/netlink"
    20  )
    21  
    22  var (
    23  	networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error)
    24  )
    25  
    26  // CheckRouteOverlaps checks whether the passed network overlaps with any existing routes
    27  func CheckRouteOverlaps(toCheck *net.IPNet) error {
    28  	if networkGetRoutesFct == nil {
    29  		networkGetRoutesFct = ns.NlHandle().RouteList
    30  	}
    31  	networks, err := networkGetRoutesFct(nil, netlink.FAMILY_V4)
    32  	if err != nil {
    33  		return err
    34  	}
    35  	for _, network := range networks {
    36  		if network.Dst != nil && network.Scope == netlink.SCOPE_LINK && NetworkOverlaps(toCheck, network.Dst) {
    37  			return ErrNetworkOverlaps
    38  		}
    39  	}
    40  	return nil
    41  }
    42  
    43  // GenerateIfaceName returns an interface name using the passed in
    44  // prefix and the length of random bytes. The api ensures that the
    45  // there are is no interface which exists with that name.
    46  func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, error) {
    47  	linkByName := netlink.LinkByName
    48  	if nlh != nil {
    49  		linkByName = nlh.LinkByName
    50  	}
    51  	for i := 0; i < 3; i++ {
    52  		name, err := GenerateRandomName(prefix, len)
    53  		if err != nil {
    54  			continue
    55  		}
    56  		_, err = linkByName(name)
    57  		if err != nil {
    58  			if strings.Contains(err.Error(), "not found") {
    59  				return name, nil
    60  			}
    61  			return "", err
    62  		}
    63  	}
    64  	return "", types.InternalErrorf("could not generate interface name")
    65  }
    66  
    67  // ElectInterfaceAddresses looks for an interface on the OS with the
    68  // specified name and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
    69  // If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
    70  // If the interface does not exist, it chooses from a predefined
    71  // list the first IPv4 address which does not conflict with other
    72  // interfaces on the system.
    73  func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
    74  	var (
    75  		v4Nets []*net.IPNet
    76  		v6Nets []*net.IPNet
    77  	)
    78  
    79  	defer osl.InitOSContext()()
    80  
    81  	link, _ := ns.NlHandle().LinkByName(name)
    82  	if link != nil {
    83  		v4addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V4)
    84  		if err != nil {
    85  			return nil, nil, err
    86  		}
    87  		v6addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V6)
    88  		if err != nil {
    89  			return nil, nil, err
    90  		}
    91  		for _, nlAddr := range v4addr {
    92  			v4Nets = append(v4Nets, nlAddr.IPNet)
    93  		}
    94  		for _, nlAddr := range v6addr {
    95  			v6Nets = append(v6Nets, nlAddr.IPNet)
    96  		}
    97  	}
    98  
    99  	if link == nil || len(v4Nets) == 0 {
   100  		// Choose from predefined local scope networks
   101  		v4Net, err := FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks)
   102  		if err != nil {
   103  			return nil, nil, errors.Wrapf(err, "PredefinedLocalScopeDefaultNetworks List: %+v",
   104  				ipamutils.PredefinedLocalScopeDefaultNetworks)
   105  		}
   106  		v4Nets = append(v4Nets, v4Net)
   107  	}
   108  
   109  	return v4Nets, v6Nets, nil
   110  }
   111  
   112  // FindAvailableNetwork returns a network from the passed list which does not
   113  // overlap with existing interfaces in the system
   114  func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
   115  	// We don't check for an error here, because we don't really care if we
   116  	// can't read /etc/resolv.conf. So instead we skip the append if resolvConf
   117  	// is nil. It either doesn't exist, or we can't read it for some reason.
   118  	var nameservers []string
   119  	if rc, err := resolvconf.Get(); err == nil {
   120  		nameservers = resolvconf.GetNameserversAsCIDR(rc.Content)
   121  	}
   122  	for _, nw := range list {
   123  		if err := CheckNameserverOverlaps(nameservers, nw); err == nil {
   124  			if err := CheckRouteOverlaps(nw); err == nil {
   125  				return nw, nil
   126  			}
   127  		}
   128  	}
   129  	return nil, fmt.Errorf("no available network")
   130  }