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