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