libnet: Endpoint: remove isAnonymous & myAliases
**- What I did**

The `Endpoint` struct was containing two confusing fields:

1. `isAnonymous`: was set on endpoints which name shouldn't be taken into account when inserting DNS records into libnetwork's `Controller.svcRecords` (and into the NetworkDB). However, in that case the endpoint's aliases would still be used to create DNS records; thus, making those "anonymous endpoints" not so anonymous.
2. `myAliases`: there's also an `aliases` field in the `Endpoint` struct. `myAliases` was storing extra DNS names for the endpoint, while `aliases` stores extra DNS names for _other_ endpoints (but those extra DNS names are only accessible for the endpoint storing them -- yeah, it's confusing too).

To make it worse, the code that built the list of DNS names for a given endpoint was split in two:

1. `updateNetworkConfig` (in the `daemon` pkg) was adding the endpoint short ID and hostname to the list of aliases ;
2. In libnetwork, to handle "anonymous" endpoints as described above.

This PR replaces both fields with a new `DNSNames` containing _all_ (non-fully qualified) DNS names for a given endpoint. It's now built by the daemon during `updateNetworkConfig` and reimplements the same logic for aliases as before (a test has been added to make sure of that). An "anonymous" endpoint is now an endpoint with no `DNSNames`.

This new field is also stored in the "operational data" (ie. state) of the `EndpointSettings` struct exposed by the API via `GET /containers/{name:.*}/json`, making it easier for end-users and scripts to know every DNS names a container has on a specific network.

**- How to verify it**

`docker run --network testnet` with a variety of:

* `--name` ;
* `--hostname` ;
* `--network-alias` ;

**- A picture of a cute animal (not mandatory but encouraged)**

![](https://www.nhm.ac.uk/resources/visit/wpy/2018/large/webp/14.webp)

api/types/network/endpoint.go
package network

import (
	"errors"
	"fmt"
	"net"

	"github.com/docker/docker/internal/multierror"
)

// EndpointSettings stores the network endpoint details
type EndpointSettings struct {
	// Configurations
	IPAMConfig *EndpointIPAMConfig
	Links      []string
	Aliases    []string
	MacAddress string
	// Operational data
	NetworkID           string
	EndpointID          string
	Gateway             string
	IPAddress           string
	IPPrefixLen         int
	IPv6Gateway         string
	GlobalIPv6Address   string
	GlobalIPv6PrefixLen int
	DriverOpts          map[string]string
}

// Copy makes a deep copy of `EndpointSettings`
func (es *EndpointSettings) Copy() *EndpointSettings {
	epCopy := *es
	if es.IPAMConfig != nil {
		epCopy.IPAMConfig = es.IPAMConfig.Copy()
	}

	if es.Links != nil {
		links := make([]string, 0, len(es.Links))
		epCopy.Links = append(links, es.Links...)
	}

	if es.Aliases != nil {
		aliases := make([]string, 0, len(es.Aliases))
		epCopy.Aliases = append(aliases, es.Aliases...)
	}
	return &epCopy
}

// EndpointIPAMConfig represents IPAM configurations for the endpoint
type EndpointIPAMConfig struct {
	IPv4Address  string   `json:",omitempty"`
	IPv6Address  string   `json:",omitempty"`
	LinkLocalIPs []string `json:",omitempty"`
}

// Copy makes a copy of the endpoint ipam config
func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig {
	cfgCopy := *cfg
	cfgCopy.LinkLocalIPs = make([]string, 0, len(cfg.LinkLocalIPs))
	cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, cfg.LinkLocalIPs...)
	return &cfgCopy
}

// NetworkSubnet describes a user-defined subnet for a specific network. It's only used to validate if an
// EndpointIPAMConfig is valid for a specific network.
type NetworkSubnet interface {
	// Contains checks whether the NetworkSubnet contains [addr].
	Contains(addr net.IP) bool
	// IsStatic checks whether the subnet was statically allocated (ie. user-defined).
	IsStatic() bool
}

// IsInRange checks whether static IP addresses are valid in a specific network.
func (cfg *EndpointIPAMConfig) IsInRange(v4Subnets []NetworkSubnet, v6Subnets []NetworkSubnet) error {
	var errs []error

	if err := validateEndpointIPAddress(cfg.IPv4Address, v4Subnets); err != nil {
		errs = append(errs, err)
	}
	if err := validateEndpointIPAddress(cfg.IPv6Address, v6Subnets); err != nil {
		errs = append(errs, err)
	}

	return multierror.Join(errs...)
}

func validateEndpointIPAddress(epAddr string, ipamSubnets []NetworkSubnet) error {
	if epAddr == "" {
		return nil
	}

	var staticSubnet bool
	parsedAddr := net.ParseIP(epAddr)
	for _, subnet := range ipamSubnets {
		if subnet.IsStatic() {
			staticSubnet = true
			if subnet.Contains(parsedAddr) {
				return nil
			}
		}
	}

	if staticSubnet {
		return fmt.Errorf("no configured subnet or ip-range contain the IP address %s", epAddr)
	}

	return errors.New("user specified IP address is supported only when connecting to networks with user configured subnets")
}

// Validate checks whether cfg is valid.
func (cfg *EndpointIPAMConfig) Validate() error {
	if cfg == nil {
		return nil
	}

	var errs []error

	if cfg.IPv4Address != "" {
		if addr := net.ParseIP(cfg.IPv4Address); addr == nil || addr.To4() == nil || addr.IsUnspecified() {
			errs = append(errs, fmt.Errorf("invalid IPv4 address: %s", cfg.IPv4Address))
		}
	}
	if cfg.IPv6Address != "" {
		if addr := net.ParseIP(cfg.IPv6Address); addr == nil || addr.To4() != nil || addr.IsUnspecified() {
			errs = append(errs, fmt.Errorf("invalid IPv6 address: %s", cfg.IPv6Address))
		}
	}
	for _, addr := range cfg.LinkLocalIPs {
		if parsed := net.ParseIP(addr); parsed == nil || parsed.IsUnspecified() {
			errs = append(errs, fmt.Errorf("invalid link-local IP address: %s", addr))
		}
	}

	return multierror.Join(errs...)
}

package network

import (
	"errors"
	"fmt"
	"net"

	"github.com/docker/docker/internal/multierror"
)

// EndpointSettings stores the network endpoint details
type EndpointSettings struct {
	// Configurations
	IPAMConfig *EndpointIPAMConfig
	Links      []string
	Aliases    []string // Aliases holds the list of extra, user-specified DNS names for this endpoint.
	MacAddress string
	// Operational data
	NetworkID           string
	EndpointID          string
	Gateway             string
	IPAddress           string
	IPPrefixLen         int
	IPv6Gateway         string
	GlobalIPv6Address   string
	GlobalIPv6PrefixLen int
	DriverOpts          map[string]string
	// DNSNames holds all the (non fully qualified) DNS names associated to this endpoint. First entry is used to
	// generate PTR records.
	DNSNames []string
}

// Copy makes a deep copy of `EndpointSettings`
func (es *EndpointSettings) Copy() *EndpointSettings {
	epCopy := *es
	if es.IPAMConfig != nil {
		epCopy.IPAMConfig = es.IPAMConfig.Copy()
	}

	if es.Links != nil {
		links := make([]string, 0, len(es.Links))
		epCopy.Links = append(links, es.Links...)
	}

	if es.Aliases != nil {
		aliases := make([]string, 0, len(es.Aliases))
		epCopy.Aliases = append(aliases, es.Aliases...)
	}

	if len(es.DNSNames) > 0 {
		epCopy.DNSNames = make([]string, len(es.DNSNames))
		copy(epCopy.DNSNames, es.DNSNames)
	}

	return &epCopy
}

// EndpointIPAMConfig represents IPAM configurations for the endpoint
type EndpointIPAMConfig struct {
	IPv4Address  string   `json:",omitempty"`
	IPv6Address  string   `json:",omitempty"`
	LinkLocalIPs []string `json:",omitempty"`
}

// Copy makes a copy of the endpoint ipam config
func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig {
	cfgCopy := *cfg
	cfgCopy.LinkLocalIPs = make([]string, 0, len(cfg.LinkLocalIPs))
	cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, cfg.LinkLocalIPs...)
	return &cfgCopy
}

// NetworkSubnet describes a user-defined subnet for a specific network. It's only used to validate if an
// EndpointIPAMConfig is valid for a specific network.
type NetworkSubnet interface {
	// Contains checks whether the NetworkSubnet contains [addr].
	Contains(addr net.IP) bool
	// IsStatic checks whether the subnet was statically allocated (ie. user-defined).
	IsStatic() bool
}

// IsInRange checks whether static IP addresses are valid in a specific network.
func (cfg *EndpointIPAMConfig) IsInRange(v4Subnets []NetworkSubnet, v6Subnets []NetworkSubnet) error {
	var errs []error

	if err := validateEndpointIPAddress(cfg.IPv4Address, v4Subnets); err != nil {
		errs = append(errs, err)
	}
	if err := validateEndpointIPAddress(cfg.IPv6Address, v6Subnets); err != nil {
		errs = append(errs, err)
	}

	return multierror.Join(errs...)
}

func validateEndpointIPAddress(epAddr string, ipamSubnets []NetworkSubnet) error {
	if epAddr == "" {
		return nil
	}

	var staticSubnet bool
	parsedAddr := net.ParseIP(epAddr)
	for _, subnet := range ipamSubnets {
		if subnet.IsStatic() {
			staticSubnet = true
			if subnet.Contains(parsedAddr) {
				return nil
			}
		}
	}

	if staticSubnet {
		return fmt.Errorf("no configured subnet or ip-range contain the IP address %s", epAddr)
	}

	return errors.New("user specified IP address is supported only when connecting to networks with user configured subnets")
}

// Validate checks whether cfg is valid.
func (cfg *EndpointIPAMConfig) Validate() error {
	if cfg == nil {
		return nil
	}

	var errs []error

	if cfg.IPv4Address != "" {
		if addr := net.ParseIP(cfg.IPv4Address); addr == nil || addr.To4() == nil || addr.IsUnspecified() {
			errs = append(errs, fmt.Errorf("invalid IPv4 address: %s", cfg.IPv4Address))
		}
	}
	if cfg.IPv6Address != "" {
		if addr := net.ParseIP(cfg.IPv6Address); addr == nil || addr.To4() != nil || addr.IsUnspecified() {
			errs = append(errs, fmt.Errorf("invalid IPv6 address: %s", cfg.IPv6Address))
		}
	}
	for _, addr := range cfg.LinkLocalIPs {
		if parsed := net.ParseIP(addr); parsed == nil || parsed.IsUnspecified() {
			errs = append(errs, fmt.Errorf("invalid link-local IP address: %s", addr))
		}
	}

	return multierror.Join(errs...)
}

Not a blocker; I guess this approach was copied from the other ones, but I don't think we need the intermediate var, and `copy` is probably the more optimized version;

```suggestion
	if len(es.DNSNames) > 0 {
		epCopy.DNSNames = make([]string, len(es.DNSNames))
		copy(epCopy.DNSNames, es.DNSNames)
	}
```
