github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/api/types/network/endpoint.go (about)

     1  package network
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  
     8  	"github.com/Prakhar-Agarwal-byte/moby/internal/multierror"
     9  )
    10  
    11  // EndpointSettings stores the network endpoint details
    12  type EndpointSettings struct {
    13  	// Configurations
    14  	IPAMConfig *EndpointIPAMConfig
    15  	Links      []string
    16  	Aliases    []string
    17  	// Operational data
    18  	NetworkID           string
    19  	EndpointID          string
    20  	Gateway             string
    21  	IPAddress           string
    22  	IPPrefixLen         int
    23  	IPv6Gateway         string
    24  	GlobalIPv6Address   string
    25  	GlobalIPv6PrefixLen int
    26  	MacAddress          string
    27  	DriverOpts          map[string]string
    28  }
    29  
    30  // Copy makes a deep copy of `EndpointSettings`
    31  func (es *EndpointSettings) Copy() *EndpointSettings {
    32  	epCopy := *es
    33  	if es.IPAMConfig != nil {
    34  		epCopy.IPAMConfig = es.IPAMConfig.Copy()
    35  	}
    36  
    37  	if es.Links != nil {
    38  		links := make([]string, 0, len(es.Links))
    39  		epCopy.Links = append(links, es.Links...)
    40  	}
    41  
    42  	if es.Aliases != nil {
    43  		aliases := make([]string, 0, len(es.Aliases))
    44  		epCopy.Aliases = append(aliases, es.Aliases...)
    45  	}
    46  	return &epCopy
    47  }
    48  
    49  // EndpointIPAMConfig represents IPAM configurations for the endpoint
    50  type EndpointIPAMConfig struct {
    51  	IPv4Address  string   `json:",omitempty"`
    52  	IPv6Address  string   `json:",omitempty"`
    53  	LinkLocalIPs []string `json:",omitempty"`
    54  }
    55  
    56  // Copy makes a copy of the endpoint ipam config
    57  func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig {
    58  	cfgCopy := *cfg
    59  	cfgCopy.LinkLocalIPs = make([]string, 0, len(cfg.LinkLocalIPs))
    60  	cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, cfg.LinkLocalIPs...)
    61  	return &cfgCopy
    62  }
    63  
    64  // NetworkSubnet describes a user-defined subnet for a specific network. It's only used to validate if an
    65  // EndpointIPAMConfig is valid for a specific network.
    66  type NetworkSubnet interface {
    67  	// Contains checks whether the NetworkSubnet contains [addr].
    68  	Contains(addr net.IP) bool
    69  	// IsStatic checks whether the subnet was statically allocated (ie. user-defined).
    70  	IsStatic() bool
    71  }
    72  
    73  // IsInRange checks whether static IP addresses are valid in a specific network.
    74  func (cfg *EndpointIPAMConfig) IsInRange(v4Subnets []NetworkSubnet, v6Subnets []NetworkSubnet) error {
    75  	var errs []error
    76  
    77  	if err := validateEndpointIPAddress(cfg.IPv4Address, v4Subnets); err != nil {
    78  		errs = append(errs, err)
    79  	}
    80  	if err := validateEndpointIPAddress(cfg.IPv6Address, v6Subnets); err != nil {
    81  		errs = append(errs, err)
    82  	}
    83  
    84  	return multierror.Join(errs...)
    85  }
    86  
    87  func validateEndpointIPAddress(epAddr string, ipamSubnets []NetworkSubnet) error {
    88  	if epAddr == "" {
    89  		return nil
    90  	}
    91  
    92  	var staticSubnet bool
    93  	parsedAddr := net.ParseIP(epAddr)
    94  	for _, subnet := range ipamSubnets {
    95  		if subnet.IsStatic() {
    96  			staticSubnet = true
    97  			if subnet.Contains(parsedAddr) {
    98  				return nil
    99  			}
   100  		}
   101  	}
   102  
   103  	if staticSubnet {
   104  		return fmt.Errorf("no configured subnet or ip-range contain the IP address %s", epAddr)
   105  	}
   106  
   107  	return errors.New("user specified IP address is supported only when connecting to networks with user configured subnets")
   108  }
   109  
   110  // Validate checks whether cfg is valid.
   111  func (cfg *EndpointIPAMConfig) Validate() error {
   112  	if cfg == nil {
   113  		return nil
   114  	}
   115  
   116  	var errs []error
   117  
   118  	if cfg.IPv4Address != "" {
   119  		if addr := net.ParseIP(cfg.IPv4Address); addr == nil || addr.To4() == nil || addr.IsUnspecified() {
   120  			errs = append(errs, fmt.Errorf("invalid IPv4 address: %s", cfg.IPv4Address))
   121  		}
   122  	}
   123  	if cfg.IPv6Address != "" {
   124  		if addr := net.ParseIP(cfg.IPv6Address); addr == nil || addr.To4() != nil || addr.IsUnspecified() {
   125  			errs = append(errs, fmt.Errorf("invalid IPv6 address: %s", cfg.IPv6Address))
   126  		}
   127  	}
   128  	for _, addr := range cfg.LinkLocalIPs {
   129  		if parsed := net.ParseIP(addr); parsed == nil || parsed.IsUnspecified() {
   130  			errs = append(errs, fmt.Errorf("invalid link-local IP address: %s", addr))
   131  		}
   132  	}
   133  
   134  	return multierror.Join(errs...)
   135  }