github.com/adityamillind98/moby@v23.0.0-rc.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 "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/osl" 16 "github.com/docker/docker/libnetwork/resolvconf" 17 "github.com/docker/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 v4Nets, v6Nets []*net.IPNet 75 76 defer osl.InitOSContext()() 77 78 link, _ := ns.NlHandle().LinkByName(name) 79 if link != nil { 80 v4addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V4) 81 if err != nil { 82 return nil, nil, err 83 } 84 v6addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V6) 85 if err != nil { 86 return nil, nil, err 87 } 88 for _, nlAddr := range v4addr { 89 v4Nets = append(v4Nets, nlAddr.IPNet) 90 } 91 for _, nlAddr := range v6addr { 92 v6Nets = append(v6Nets, nlAddr.IPNet) 93 } 94 } 95 96 if link == nil || len(v4Nets) == 0 { 97 // Choose from predefined local scope networks 98 v4Net, err := FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks) 99 if err != nil { 100 return nil, nil, errors.Wrapf(err, "PredefinedLocalScopeDefaultNetworks List: %+v", 101 ipamutils.PredefinedLocalScopeDefaultNetworks) 102 } 103 v4Nets = append(v4Nets, v4Net) 104 } 105 106 return v4Nets, v6Nets, nil 107 } 108 109 // FindAvailableNetwork returns a network from the passed list which does not 110 // overlap with existing interfaces in the system 111 func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) { 112 // We don't check for an error here, because we don't really care if we 113 // can't read /etc/resolv.conf. So instead we skip the append if resolvConf 114 // is nil. It either doesn't exist, or we can't read it for some reason. 115 var nameservers []string 116 if rc, err := resolvconf.Get(); err == nil { 117 nameservers = resolvconf.GetNameserversAsCIDR(rc.Content) 118 } 119 for _, nw := range list { 120 if err := CheckNameserverOverlaps(nameservers, nw); err == nil { 121 if err := CheckRouteOverlaps(nw); err == nil { 122 return nw, nil 123 } 124 } 125 } 126 return nil, fmt.Errorf("no available network") 127 }