github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/network/network.go (about)

     1  package network
     2  
     3  import (
     4  	"encoding/json"
     5  	"net"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	"github.com/containernetworking/cni/pkg/types"
    10  	"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
    11  	"github.com/containers/common/pkg/config"
    12  	"github.com/containers/podman/v2/libpod/define"
    13  	"github.com/containers/podman/v2/pkg/rootless"
    14  	"github.com/containers/podman/v2/pkg/util"
    15  	"github.com/pkg/errors"
    16  	"github.com/sirupsen/logrus"
    17  )
    18  
    19  // DefaultNetworkDriver is the default network type used
    20  var DefaultNetworkDriver = "bridge"
    21  
    22  // SupportedNetworkDrivers describes the list of supported drivers
    23  var SupportedNetworkDrivers = []string{DefaultNetworkDriver}
    24  
    25  // isSupportedDriver checks if the user provided driver is supported
    26  func isSupportedDriver(driver string) error {
    27  	if util.StringInSlice(driver, SupportedNetworkDrivers) {
    28  		return nil
    29  	}
    30  	return errors.Errorf("driver '%s' is not supported", driver)
    31  }
    32  
    33  // GetLiveNetworks returns a slice of networks representing what the system
    34  // has defined as network interfaces
    35  func GetLiveNetworks() ([]*net.IPNet, error) {
    36  	addrs, err := net.InterfaceAddrs()
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	nets := make([]*net.IPNet, 0, len(addrs))
    41  	for _, address := range addrs {
    42  		_, n, err := net.ParseCIDR(address.String())
    43  		if err != nil {
    44  			return nil, err
    45  		}
    46  		nets = append(nets, n)
    47  	}
    48  	return nets, nil
    49  }
    50  
    51  // GetLiveNetworkNames returns a list of network interfaces on the system
    52  func GetLiveNetworkNames() ([]string, error) {
    53  	liveInterfaces, err := net.Interfaces()
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	interfaceNames := make([]string, 0, len(liveInterfaces))
    58  	for _, i := range liveInterfaces {
    59  		interfaceNames = append(interfaceNames, i.Name)
    60  	}
    61  	return interfaceNames, nil
    62  }
    63  
    64  // GetFreeNetwork looks for a free network according to existing cni configuration
    65  // files and network interfaces.
    66  func GetFreeNetwork(config *config.Config) (*net.IPNet, error) {
    67  	networks, err := GetNetworksFromFilesystem(config)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	liveNetworks, err := GetLiveNetworks()
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	nextNetwork, err := GetDefaultPodmanNetwork()
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	logrus.Debugf("default network is %s", nextNetwork.String())
    80  	for {
    81  		newNetwork, err := NextSubnet(nextNetwork)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  		logrus.Debugf("checking if network %s intersects with other cni networks", nextNetwork.String())
    86  		if intersectsConfig, _ := networkIntersectsWithNetworks(newNetwork, allocatorToIPNets(networks)); intersectsConfig {
    87  			logrus.Debugf("network %s is already being used by a cni configuration", nextNetwork.String())
    88  			nextNetwork = newNetwork
    89  			continue
    90  		}
    91  		logrus.Debugf("checking if network %s intersects with any network interfaces", nextNetwork.String())
    92  		if intersectsLive, _ := networkIntersectsWithNetworks(newNetwork, liveNetworks); !intersectsLive {
    93  			break
    94  		}
    95  		logrus.Debugf("network %s is being used by a network interface", nextNetwork.String())
    96  		nextNetwork = newNetwork
    97  	}
    98  	return nextNetwork, nil
    99  }
   100  
   101  func allocatorToIPNets(networks []*allocator.Net) []*net.IPNet {
   102  	var nets []*net.IPNet
   103  	for _, network := range networks {
   104  		if len(network.IPAM.Ranges) > 0 {
   105  			// this is the new IPAM range style
   106  			// append each subnet from ipam the rangeset
   107  			for _, r := range network.IPAM.Ranges[0] {
   108  				nets = append(nets, newIPNetFromSubnet(r.Subnet))
   109  			}
   110  		} else {
   111  			//	 looks like the old, deprecated style
   112  			nets = append(nets, newIPNetFromSubnet(network.IPAM.Subnet))
   113  		}
   114  	}
   115  	return nets
   116  }
   117  
   118  func newIPNetFromSubnet(subnet types.IPNet) *net.IPNet {
   119  	n := net.IPNet{
   120  		IP:   subnet.IP,
   121  		Mask: subnet.Mask,
   122  	}
   123  	return &n
   124  }
   125  
   126  func networkIntersectsWithNetworks(n *net.IPNet, networklist []*net.IPNet) (bool, *net.IPNet) {
   127  	for _, nw := range networklist {
   128  		if networkIntersect(n, nw) {
   129  			return true, nw
   130  		}
   131  	}
   132  	return false, nil
   133  }
   134  
   135  func networkIntersect(n1, n2 *net.IPNet) bool {
   136  	return n2.Contains(n1.IP) || n1.Contains(n2.IP)
   137  }
   138  
   139  // ValidateUserNetworkIsAvailable returns via an error if a network is available
   140  // to be used
   141  func ValidateUserNetworkIsAvailable(config *config.Config, userNet *net.IPNet) error {
   142  	if len(userNet.IP) == 0 || len(userNet.Mask) == 0 {
   143  		return errors.Errorf("network %s's ip or mask cannot be empty", userNet.String())
   144  	}
   145  
   146  	ones, bit := userNet.Mask.Size()
   147  	if ones == 0 || bit == 0 {
   148  		return errors.Errorf("network %s's mask is invalid", userNet.String())
   149  	}
   150  
   151  	networks, err := GetNetworksFromFilesystem(config)
   152  	if err != nil {
   153  		return err
   154  	}
   155  	liveNetworks, err := GetLiveNetworks()
   156  	if err != nil {
   157  		return err
   158  	}
   159  	logrus.Debugf("checking if network %s exists in cni networks", userNet.String())
   160  	if intersectsConfig, _ := networkIntersectsWithNetworks(userNet, allocatorToIPNets(networks)); intersectsConfig {
   161  		return errors.Errorf("network %s is already being used by a cni configuration", userNet.String())
   162  	}
   163  	logrus.Debugf("checking if network %s exists in any network interfaces", userNet.String())
   164  	if intersectsLive, _ := networkIntersectsWithNetworks(userNet, liveNetworks); intersectsLive {
   165  		return errors.Errorf("network %s is being used by a network interface", userNet.String())
   166  	}
   167  	return nil
   168  }
   169  
   170  // RemoveNetwork removes a given network by name.  If the network has container associated with it, that
   171  // must be handled outside the context of this.
   172  func RemoveNetwork(config *config.Config, name string) error {
   173  	l, err := acquireCNILock(filepath.Join(config.Engine.TmpDir, LockFileName))
   174  	if err != nil {
   175  		return err
   176  	}
   177  	defer l.releaseCNILock()
   178  	cniPath, err := GetCNIConfigPathByName(config, name)
   179  	if err != nil {
   180  		return err
   181  	}
   182  	// Before we delete the configuration file, we need to make sure we can read and parse
   183  	// it to get the network interface name so we can remove that too
   184  	interfaceName, err := GetInterfaceNameFromConfig(cniPath)
   185  	if err == nil {
   186  		// Don't try to remove the network interface if we are not root
   187  		if !rootless.IsRootless() {
   188  			liveNetworkNames, err := GetLiveNetworkNames()
   189  			if err != nil {
   190  				return errors.Wrapf(err, "failed to get live network names")
   191  			}
   192  			if util.StringInSlice(interfaceName, liveNetworkNames) {
   193  				if err := RemoveInterface(interfaceName); err != nil {
   194  					return errors.Wrapf(err, "failed to delete the network interface %q", interfaceName)
   195  				}
   196  			}
   197  		}
   198  	} else if err != ErrNoSuchNetworkInterface {
   199  		// Don't error if we couldn't find the network interface name
   200  		return err
   201  	}
   202  	// Remove the configuration file
   203  	if err := os.Remove(cniPath); err != nil {
   204  		return errors.Wrap(err, "failed to remove network configuration")
   205  	}
   206  	return nil
   207  }
   208  
   209  // InspectNetwork reads a CNI config and returns its configuration
   210  func InspectNetwork(config *config.Config, name string) (map[string]interface{}, error) {
   211  	b, err := ReadRawCNIConfByName(config, name)
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  	rawList := make(map[string]interface{})
   216  	err = json.Unmarshal(b, &rawList)
   217  	return rawList, err
   218  }
   219  
   220  // Exists says whether a given network exists or not; it meant
   221  // specifically for restful responses so 404s can be used
   222  func Exists(config *config.Config, name string) (bool, error) {
   223  	_, err := ReadRawCNIConfByName(config, name)
   224  	if err != nil {
   225  		if errors.Cause(err) == define.ErrNoSuchNetwork {
   226  			return false, nil
   227  		}
   228  		return false, err
   229  	}
   230  	return true, nil
   231  }