github.com/rawahars/moby@v24.0.4+incompatible/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  	"net"
    10  	"os"
    11  
    12  	"github.com/docker/docker/libnetwork/ns"
    13  	"github.com/docker/docker/libnetwork/resolvconf"
    14  	"github.com/docker/docker/libnetwork/types"
    15  	"github.com/pkg/errors"
    16  	"github.com/vishvananda/netlink"
    17  )
    18  
    19  var networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error)
    20  
    21  // CheckRouteOverlaps checks whether the passed network overlaps with any existing routes
    22  func CheckRouteOverlaps(toCheck *net.IPNet) error {
    23  	networkGetRoutesFct := networkGetRoutesFct
    24  	if networkGetRoutesFct == nil {
    25  		networkGetRoutesFct = ns.NlHandle().RouteList
    26  	}
    27  	networks, err := networkGetRoutesFct(nil, netlink.FAMILY_V4)
    28  	if err != nil {
    29  		return err
    30  	}
    31  	for _, network := range networks {
    32  		if network.Dst != nil && network.Scope == netlink.SCOPE_LINK && NetworkOverlaps(toCheck, network.Dst) {
    33  			return ErrNetworkOverlaps
    34  		}
    35  	}
    36  	return nil
    37  }
    38  
    39  // GenerateIfaceName returns an interface name using the passed in
    40  // prefix and the length of random bytes. The api ensures that the
    41  // there are is no interface which exists with that name.
    42  func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, error) {
    43  	linkByName := netlink.LinkByName
    44  	if nlh != nil {
    45  		linkByName = nlh.LinkByName
    46  	}
    47  	for i := 0; i < 3; i++ {
    48  		name, err := GenerateRandomName(prefix, len)
    49  		if err != nil {
    50  			return "", err
    51  		}
    52  		_, err = linkByName(name)
    53  		if err != nil {
    54  			if errors.As(err, &netlink.LinkNotFoundError{}) {
    55  				return name, nil
    56  			}
    57  			return "", err
    58  		}
    59  	}
    60  	return "", types.InternalErrorf("could not generate interface name")
    61  }
    62  
    63  // FindAvailableNetwork returns a network from the passed list which does not
    64  // overlap with existing interfaces in the system
    65  func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
    66  	// We don't check for an error here, because we don't really care if we
    67  	// can't read /etc/resolv.conf. So instead we skip the append if resolvConf
    68  	// is nil. It either doesn't exist, or we can't read it for some reason.
    69  	var nameservers []string
    70  	if rc, err := os.ReadFile(resolvconf.Path()); err == nil {
    71  		nameservers = resolvconf.GetNameserversAsCIDR(rc)
    72  	}
    73  	for _, nw := range list {
    74  		if err := CheckNameserverOverlaps(nameservers, nw); err == nil {
    75  			if err := CheckRouteOverlaps(nw); err == nil {
    76  				return nw, nil
    77  			}
    78  		}
    79  	}
    80  	return nil, errors.New("no available network")
    81  }