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