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 }