From d6899ca5a5dcd5428ad4a47dc2fdfc3c0659dc7f Mon Sep 17 00:00:00 2001 From: Cory Snider Date: Thu, 2 Oct 2025 21:50:35 -0400 Subject: [PATCH] api/types/registry: use netip types as appropriate Signed-off-by: Cory Snider Signed-off-by: Sebastiaan van Stijn --- api/types/registry/registry.go | 33 +------------- daemon/pkg/registry/config.go | 43 +++++++++---------- daemon/pkg/registry/search_test.go | 20 ++------- .../moby/moby/api/types/registry/registry.go | 33 +------------- 4 files changed, 28 insertions(+), 101 deletions(-) diff --git a/api/types/registry/registry.go b/api/types/registry/registry.go index 97c396fe0c..ef5a486ed6 100644 --- a/api/types/registry/registry.go +++ b/api/types/registry/registry.go @@ -1,15 +1,14 @@ package registry import ( - "encoding/json" - "net" + "net/netip" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // ServiceConfig stores daemon registry services configuration. type ServiceConfig struct { - InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"` + InsecureRegistryCIDRs []netip.Prefix `json:"InsecureRegistryCIDRs"` IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"` Mirrors []string @@ -17,34 +16,6 @@ type ServiceConfig struct { ExtraFields map[string]any `json:"-"` } -// NetIPNet is the net.IPNet type, which can be marshalled and -// unmarshalled to JSON -type NetIPNet net.IPNet - -// String returns the CIDR notation of ipnet -func (ipnet *NetIPNet) String() string { - return (*net.IPNet)(ipnet).String() -} - -// MarshalJSON returns the JSON representation of the IPNet -func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) { - return json.Marshal((*net.IPNet)(ipnet).String()) -} - -// UnmarshalJSON sets the IPNet from a byte array of JSON -func (ipnet *NetIPNet) UnmarshalJSON(b []byte) error { - var ipnetStr string - if err := json.Unmarshal(b, &ipnetStr); err != nil { - return err - } - _, cidr, err := net.ParseCIDR(ipnetStr) - if err != nil { - return err - } - *ipnet = NetIPNet(*cidr) - return nil -} - // IndexInfo contains information about a registry // // RepositoryInfo Examples: diff --git a/daemon/pkg/registry/config.go b/daemon/pkg/registry/config.go index f828936bb4..dea7c87634 100644 --- a/daemon/pkg/registry/config.go +++ b/daemon/pkg/registry/config.go @@ -2,12 +2,15 @@ package registry import ( "context" + "maps" "net" + "net/netip" "net/url" "os" "path/filepath" "regexp" "runtime" + "slices" "strconv" "strings" "sync" @@ -103,9 +106,9 @@ func (config *serviceConfig) copy() *registry.ServiceConfig { ic[key] = value } return ®istry.ServiceConfig{ - InsecureRegistryCIDRs: append([]*registry.NetIPNet(nil), config.InsecureRegistryCIDRs...), + InsecureRegistryCIDRs: slices.Clone(config.InsecureRegistryCIDRs), IndexConfigs: ic, - Mirrors: append([]string(nil), config.Mirrors...), + Mirrors: slices.Clone(config.Mirrors), } } @@ -148,11 +151,10 @@ func (config *serviceConfig) loadInsecureRegistries(registries []string) error { registries = append(registries, "::1/128", "127.0.0.0/8") var ( - insecureRegistryCIDRs = make([]*registry.NetIPNet, 0) + insecureRegistryCIDRs = make(map[netip.Prefix]struct{}) indexConfigs = make(map[string]*registry.IndexInfo) ) -skip: for _, r := range registries { // validate insecure registry if _, err := ValidateIndexName(r); err != nil { @@ -169,17 +171,9 @@ skip: } } // Check if CIDR was passed to --insecure-registry - _, ipnet, err := net.ParseCIDR(r) + ipnet, err := netip.ParsePrefix(r) if err == nil { - // Valid CIDR. If ipnet is already in config.InsecureRegistryCIDRs, skip. - data := (*registry.NetIPNet)(ipnet) - for _, value := range insecureRegistryCIDRs { - if value.IP.String() == data.IP.String() && value.Mask.String() == data.Mask.String() { - continue skip - } - } - // ipnet is not found, add it in config.InsecureRegistryCIDRs - insecureRegistryCIDRs = append(insecureRegistryCIDRs, data) + insecureRegistryCIDRs[ipnet.Masked()] = struct{}{} } else { if err := validateHostPort(r); err != nil { return invalidParamWrapf(err, "insecure registry %s is not valid", r) @@ -201,7 +195,7 @@ skip: Secure: true, Official: true, } - config.InsecureRegistryCIDRs = insecureRegistryCIDRs + config.InsecureRegistryCIDRs = slices.Collect(maps.Keys(insecureRegistryCIDRs)) config.IndexConfigs = indexConfigs return nil @@ -234,7 +228,7 @@ var lookupIP = net.LookupIP // isCIDRMatch returns true if urlHost matches an element of cidrs. urlHost is a URL.Host ("host:port" or "host") // where the `host` part can be either a domain name or an IP address. If it is a domain name, then it will be // resolved to IP addresses for matching. If resolution fails, false is returned. -func isCIDRMatch(cidrs []*registry.NetIPNet, urlHost string) bool { +func isCIDRMatch(cidrs []netip.Prefix, urlHost string) bool { if len(cidrs) == 0 { return false } @@ -245,23 +239,26 @@ func isCIDRMatch(cidrs []*registry.NetIPNet, urlHost string) bool { host = urlHost } - var addresses []net.IP - if ip := net.ParseIP(host); ip != nil { + addresses := make(map[netip.Addr]struct{}) + if ip, err := netip.ParseAddr(host); err == nil { // Host is an IP-address. - addresses = append(addresses, ip) + addresses[ip] = struct{}{} } else { // Try to resolve the host's IP-address. - addresses, err = lookupIP(host) + ips, err := lookupIP(host) if err != nil { // We failed to resolve the host; assume there's no match. return false } + for _, ip := range ips { + addr, _ := netip.AddrFromSlice(ip) + addresses[addr] = struct{}{} + } } - for _, addr := range addresses { + for addr := range addresses { for _, ipnet := range cidrs { - // check if the addr falls in the subnet - if (*net.IPNet)(ipnet).Contains(addr) { + if ipnet.Contains(addr.Unmap()) { return true } } diff --git a/daemon/pkg/registry/search_test.go b/daemon/pkg/registry/search_test.go index df48e99aa8..fe2f0046fa 100644 --- a/daemon/pkg/registry/search_test.go +++ b/daemon/pkg/registry/search_test.go @@ -3,10 +3,10 @@ package registry import ( "context" "encoding/json" - "net" "net/http" "net/http/httptest" "net/http/httputil" + "net/netip" "testing" cerrdefs "github.com/containerd/errdefs" @@ -420,18 +420,6 @@ func TestSearch(t *testing.T) { func TestNewIndexInfo(t *testing.T) { overrideLookupIP(t) - // ipv6Loopback is the CIDR for the IPv6 loopback address ("::1"); "::1/128" - ipv6Loopback := &net.IPNet{ - IP: net.IPv6loopback, - Mask: net.CIDRMask(128, 128), - } - - // ipv4Loopback is the CIDR for IPv4 loopback addresses ("127.0.0.0/8") - ipv4Loopback := &net.IPNet{ - IP: net.IPv4(127, 0, 0, 0), - Mask: net.CIDRMask(8, 32), - } - // emptyServiceConfig is a default service-config for situations where // no config-file is available (e.g. when used in the CLI). It won't // have mirrors configured, but does have the default insecure registry @@ -445,9 +433,9 @@ func TestNewIndexInfo(t *testing.T) { Official: true, }, }, - InsecureRegistryCIDRs: []*registry.NetIPNet{ - (*registry.NetIPNet)(ipv6Loopback), - (*registry.NetIPNet)(ipv4Loopback), + InsecureRegistryCIDRs: []netip.Prefix{ + netip.MustParsePrefix("::1/128"), + netip.MustParsePrefix("127.0.0.0/8"), }, } diff --git a/vendor/github.com/moby/moby/api/types/registry/registry.go b/vendor/github.com/moby/moby/api/types/registry/registry.go index 97c396fe0c..ef5a486ed6 100644 --- a/vendor/github.com/moby/moby/api/types/registry/registry.go +++ b/vendor/github.com/moby/moby/api/types/registry/registry.go @@ -1,15 +1,14 @@ package registry import ( - "encoding/json" - "net" + "net/netip" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // ServiceConfig stores daemon registry services configuration. type ServiceConfig struct { - InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"` + InsecureRegistryCIDRs []netip.Prefix `json:"InsecureRegistryCIDRs"` IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"` Mirrors []string @@ -17,34 +16,6 @@ type ServiceConfig struct { ExtraFields map[string]any `json:"-"` } -// NetIPNet is the net.IPNet type, which can be marshalled and -// unmarshalled to JSON -type NetIPNet net.IPNet - -// String returns the CIDR notation of ipnet -func (ipnet *NetIPNet) String() string { - return (*net.IPNet)(ipnet).String() -} - -// MarshalJSON returns the JSON representation of the IPNet -func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) { - return json.Marshal((*net.IPNet)(ipnet).String()) -} - -// UnmarshalJSON sets the IPNet from a byte array of JSON -func (ipnet *NetIPNet) UnmarshalJSON(b []byte) error { - var ipnetStr string - if err := json.Unmarshal(b, &ipnetStr); err != nil { - return err - } - _, cidr, err := net.ParseCIDR(ipnetStr) - if err != nil { - return err - } - *ipnet = NetIPNet(*cidr) - return nil -} - // IndexInfo contains information about a registry // // RepositoryInfo Examples: