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