Skip to content

Commit 02b6c69

Browse files
committed
Allow fallback across default ports
When no port is specified, allow falling back from 443 to 80 when http is specified along with a TLS configuration. Signed-off-by: Derek McGowan <[email protected]>
1 parent d4148d9 commit 02b6c69

File tree

4 files changed

+61
-15
lines changed

4 files changed

+61
-15
lines changed

core/remotes/docker/config/hosts.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ import (
3030
"strings"
3131
"time"
3232

33-
"github.com/containerd/containerd/v2/core/remotes/docker"
3433
"github.com/containerd/errdefs"
3534
"github.com/containerd/log"
3635
"github.com/pelletier/go-toml/v2"
3736
tomlu "github.com/pelletier/go-toml/v2/unstable"
37+
38+
"github.com/containerd/containerd/v2/core/remotes/docker"
3839
)
3940

4041
// UpdateClientFunc is a function that lets you to amend http Client behavior used by registry clients.
@@ -250,7 +251,7 @@ func ConfigureHosts(ctx context.Context, options HostOptions) docker.RegistryHos
250251
// the request twice or consuming the request body.
251252
if host.scheme == "http" && explicitTLS {
252253
_, port, _ := net.SplitHostPort(host.host)
253-
if port != "" && port != "80" {
254+
if port != "80" {
254255
log.G(ctx).WithField("host", host.host).Info("host will try HTTPS first since it is configured for HTTP with a TLS configuration, consider changing host to HTTPS or removing unused TLS configuration")
255256
host.scheme = "https"
256257
rhosts[i].Client.Transport = docker.NewHTTPFallback(rhosts[i].Client.Transport)

core/remotes/docker/config/hosts_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ import (
2626
"path/filepath"
2727
"testing"
2828

29-
"github.com/containerd/containerd/v2/core/remotes/docker"
3029
"github.com/containerd/log/logtest"
30+
31+
"github.com/containerd/containerd/v2/core/remotes/docker"
3132
)
3233

3334
const allCaps = docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityPush
@@ -361,8 +362,8 @@ func TestHTTPFallback(t *testing.T) {
361362
InsecureSkipVerify: true,
362363
},
363364
},
364-
expectedScheme: "http",
365-
usesFallback: false,
365+
expectedScheme: "https",
366+
usesFallback: true,
366367
},
367368
{
368369
host: "localhost",
@@ -402,8 +403,8 @@ func TestHTTPFallback(t *testing.T) {
402403
InsecureSkipVerify: true,
403404
},
404405
},
405-
expectedScheme: "http",
406-
usesFallback: false,
406+
expectedScheme: "https",
407+
usesFallback: true,
407408
},
408409
{
409410
host: "example.com:5000",

core/remotes/docker/resolver.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,15 @@ import (
2525
"net"
2626
"net/http"
2727
"net/url"
28+
"os"
2829
"path"
2930
"strings"
31+
"syscall"
32+
33+
"github.com/containerd/errdefs"
34+
"github.com/containerd/log"
35+
"github.com/opencontainers/go-digest"
36+
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
3037

3138
"github.com/containerd/containerd/v2/core/images"
3239
"github.com/containerd/containerd/v2/core/remotes"
@@ -35,10 +42,6 @@ import (
3542
"github.com/containerd/containerd/v2/pkg/reference"
3643
"github.com/containerd/containerd/v2/pkg/tracing"
3744
"github.com/containerd/containerd/v2/version"
38-
"github.com/containerd/errdefs"
39-
"github.com/containerd/log"
40-
"github.com/opencontainers/go-digest"
41-
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
4245
)
4346

4447
var (
@@ -732,7 +735,7 @@ func (f *httpFallback) RoundTrip(r *http.Request) (*http.Response, error) {
732735
// only fall back if the same host had previously fell back
733736
if f.host != r.URL.Host {
734737
resp, err := f.super.RoundTrip(r)
735-
if !isTLSError(err) {
738+
if !isTLSError(err) && !isPortError(err, r.URL.Host) {
736739
return resp, err
737740
}
738741
}
@@ -773,3 +776,15 @@ func isTLSError(err error) bool {
773776

774777
return false
775778
}
779+
780+
func isPortError(err error, host string) bool {
781+
if errors.Is(err, syscall.ECONNREFUSED) || os.IsTimeout(err) {
782+
if _, port, _ := net.SplitHostPort(host); port != "" {
783+
// Port is specified, will not retry on different port with scheme change
784+
return false
785+
}
786+
return true
787+
}
788+
789+
return false
790+
}

core/remotes/docker/resolver_test.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ import (
3333
"testing"
3434
"time"
3535

36-
"github.com/containerd/containerd/v2/core/remotes"
37-
"github.com/containerd/containerd/v2/core/remotes/docker/auth"
38-
remoteerrors "github.com/containerd/containerd/v2/core/remotes/errors"
3936
"github.com/containerd/errdefs"
4037
digest "github.com/opencontainers/go-digest"
4138
specs "github.com/opencontainers/image-spec/specs-go"
4239
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
40+
41+
"github.com/containerd/containerd/v2/core/remotes"
42+
"github.com/containerd/containerd/v2/core/remotes/docker/auth"
43+
remoteerrors "github.com/containerd/containerd/v2/core/remotes/errors"
4344
)
4445

4546
func TestHTTPResolver(t *testing.T) {
@@ -481,6 +482,34 @@ func TestHTTPFallbackTimeoutResolver(t *testing.T) {
481482
runBasicTest(t, "testname", sf)
482483
}
483484

485+
func TestHTTPFallbackPortError(t *testing.T) {
486+
// This test only checks the isPortError since testing the whole http fallback would
487+
// require listening on 80 and making sure nothing is listening on 443.
488+
489+
l, err := net.Listen("tcp", "127.0.0.1:0")
490+
if err != nil {
491+
t.Fatal(err)
492+
}
493+
host := l.Addr().String()
494+
err = l.Close()
495+
if err != nil {
496+
t.Fatal(err)
497+
}
498+
499+
_, err = net.Dial("tcp", host)
500+
if err == nil {
501+
t.Fatal("Dial should fail after close")
502+
}
503+
504+
if isPortError(err, host) {
505+
t.Fatalf("Expected no port error for %s with %v", host, err)
506+
}
507+
if !isPortError(err, "127.0.0.1") {
508+
t.Fatalf("Expected port error for 127.0.0.1 with %v", err)
509+
}
510+
511+
}
512+
484513
func TestResolveProxy(t *testing.T) {
485514
var (
486515
ctx = context.Background()

0 commit comments

Comments
 (0)