github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/api/types/network/endpoint.go (about) 1 package network 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 8 "github.com/docker/docker/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 // Aliases holds the list of extra, user-specified DNS names for this endpoint. 17 // MacAddress may be used to specify a MAC address when the container is created. 18 // Once the container is running, it becomes operational data (it may contain a 19 // generated address). 20 MacAddress string 21 // Operational data 22 NetworkID string 23 EndpointID string 24 Gateway string 25 IPAddress string 26 IPPrefixLen int 27 IPv6Gateway string 28 GlobalIPv6Address string 29 GlobalIPv6PrefixLen int 30 DriverOpts map[string]string 31 // DNSNames holds all the (non fully qualified) DNS names associated to this endpoint. First entry is used to 32 // generate PTR records. 33 DNSNames []string 34 } 35 36 // Copy makes a deep copy of `EndpointSettings` 37 func (es *EndpointSettings) Copy() *EndpointSettings { 38 epCopy := *es 39 if es.IPAMConfig != nil { 40 epCopy.IPAMConfig = es.IPAMConfig.Copy() 41 } 42 43 if es.Links != nil { 44 links := make([]string, 0, len(es.Links)) 45 epCopy.Links = append(links, es.Links...) 46 } 47 48 if es.Aliases != nil { 49 aliases := make([]string, 0, len(es.Aliases)) 50 epCopy.Aliases = append(aliases, es.Aliases...) 51 } 52 53 if len(es.DNSNames) > 0 { 54 epCopy.DNSNames = make([]string, len(es.DNSNames)) 55 copy(epCopy.DNSNames, es.DNSNames) 56 } 57 58 return &epCopy 59 } 60 61 // EndpointIPAMConfig represents IPAM configurations for the endpoint 62 type EndpointIPAMConfig struct { 63 IPv4Address string `json:",omitempty"` 64 IPv6Address string `json:",omitempty"` 65 LinkLocalIPs []string `json:",omitempty"` 66 } 67 68 // Copy makes a copy of the endpoint ipam config 69 func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig { 70 cfgCopy := *cfg 71 cfgCopy.LinkLocalIPs = make([]string, 0, len(cfg.LinkLocalIPs)) 72 cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, cfg.LinkLocalIPs...) 73 return &cfgCopy 74 } 75 76 // NetworkSubnet describes a user-defined subnet for a specific network. It's only used to validate if an 77 // EndpointIPAMConfig is valid for a specific network. 78 type NetworkSubnet interface { 79 // Contains checks whether the NetworkSubnet contains [addr]. 80 Contains(addr net.IP) bool 81 // IsStatic checks whether the subnet was statically allocated (ie. user-defined). 82 IsStatic() bool 83 } 84 85 // IsInRange checks whether static IP addresses are valid in a specific network. 86 func (cfg *EndpointIPAMConfig) IsInRange(v4Subnets []NetworkSubnet, v6Subnets []NetworkSubnet) error { 87 var errs []error 88 89 if err := validateEndpointIPAddress(cfg.IPv4Address, v4Subnets); err != nil { 90 errs = append(errs, err) 91 } 92 if err := validateEndpointIPAddress(cfg.IPv6Address, v6Subnets); err != nil { 93 errs = append(errs, err) 94 } 95 96 return multierror.Join(errs...) 97 } 98 99 func validateEndpointIPAddress(epAddr string, ipamSubnets []NetworkSubnet) error { 100 if epAddr == "" { 101 return nil 102 } 103 104 var staticSubnet bool 105 parsedAddr := net.ParseIP(epAddr) 106 for _, subnet := range ipamSubnets { 107 if subnet.IsStatic() { 108 staticSubnet = true 109 if subnet.Contains(parsedAddr) { 110 return nil 111 } 112 } 113 } 114 115 if staticSubnet { 116 return fmt.Errorf("no configured subnet or ip-range contain the IP address %s", epAddr) 117 } 118 119 return errors.New("user specified IP address is supported only when connecting to networks with user configured subnets") 120 } 121 122 // Validate checks whether cfg is valid. 123 func (cfg *EndpointIPAMConfig) Validate() error { 124 if cfg == nil { 125 return nil 126 } 127 128 var errs []error 129 130 if cfg.IPv4Address != "" { 131 if addr := net.ParseIP(cfg.IPv4Address); addr == nil || addr.To4() == nil || addr.IsUnspecified() { 132 errs = append(errs, fmt.Errorf("invalid IPv4 address: %s", cfg.IPv4Address)) 133 } 134 } 135 if cfg.IPv6Address != "" { 136 if addr := net.ParseIP(cfg.IPv6Address); addr == nil || addr.To4() != nil || addr.IsUnspecified() { 137 errs = append(errs, fmt.Errorf("invalid IPv6 address: %s", cfg.IPv6Address)) 138 } 139 } 140 for _, addr := range cfg.LinkLocalIPs { 141 if parsed := net.ParseIP(addr); parsed == nil || parsed.IsUnspecified() { 142 errs = append(errs, fmt.Errorf("invalid link-local IP address: %s", addr)) 143 } 144 } 145 146 return multierror.Join(errs...) 147 }