From f23b6119adacf29e33b274bd46793cfbe15bf982 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Thu, 13 Jul 2023 16:00:19 +0000 Subject: [PATCH 1/2] Fix go1.20.6 host header for unix sockets go1.20.6 made a security-related patch to header parsing that makes a path in the host header invalid. This breaks unix sockets (and probably named pipes on Windows). This change sets the `req.Host` field to override the host header field to a value go is happy with. Namely it just replaces all instances of `/` with `_` Signed-off-by: Brian Goff --- container/kill_test.go | 2 +- transport/transport.go | 30 ++++++++++++++++++++++++++---- transport/unix.go | 3 ++- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/container/kill_test.go b/container/kill_test.go index 85344e1..8835b2a 100644 --- a/container/kill_test.go +++ b/container/kill_test.go @@ -17,10 +17,10 @@ func TestKill(t *testing.T) { assert.Check(t, errdefs.IsNotFound(err), err) c, err := s.Create(ctx, "busybox:latest", WithCreateName(strings.ToLower(t.Name())), WithCreateTTY, WithCreateCmd("/bin/sh", "-c", "trap 'exit 0' SIGTERM; while true; do usleep 100000; done")) + assert.NilError(t, err) defer func() { assert.Check(t, s.Remove(ctx, c.ID(), WithRemoveForce)) }() - assert.NilError(t, err) assert.NilError(t, c.Start(ctx)) err = c.Kill(ctx, WithKillSignal("FAKESIG")) diff --git a/transport/transport.go b/transport/transport.go index bf95248..3100a27 100644 --- a/transport/transport.go +++ b/transport/transport.go @@ -9,6 +9,7 @@ import ( "net/http/httputil" "net/url" "path" + "strings" "time" ) @@ -31,10 +32,11 @@ type RequestOpt func(*http.Request) error // // Create a transport from one of the available helper functions. type Transport struct { - c *http.Client - dial func(context.Context) (net.Conn, error) - host string - scheme string + c *http.Client + dial func(context.Context) (net.Conn, error) + host string + scheme string + transform func(*http.Request) } // Do implements the Doer.Do interface @@ -50,6 +52,10 @@ func (t *Transport) Do(ctx context.Context, method, uri string, opts ...RequestO return nil, err } } + + if t.transform != nil { + t.transform(req) + } resp, err := t.c.Do(req) if err != nil { return resp, err @@ -71,6 +77,10 @@ func (t *Transport) DoRaw(ctx context.Context, method, uri string, opts ...Reque } } + if t.transform != nil { + t.transform(req) + } + conn, err := t.dial(ctx) if err != nil { return nil, err @@ -171,3 +181,15 @@ func WithAddHeaders(headers map[string][]string) RequestOpt { return nil } } + +// go1.20.6 introduced a breaking change which makes paths an invalid value for a host header +// This is problematic for us because we use the path as the URI for the request. +// If req.Host is not set OR is the same as the socket path (basically unmodified by something else) then we can rewrite it. +// If its anything else then this was changed by something else and we should not touch it. +func go120Dot6HostTransform(sock string) func(req *http.Request) { + return func(req *http.Request) { + if req.Host == "" || req.Host == sock { + req.Host = strings.Replace(sock, "/", "_", -1) + } + } +} diff --git a/transport/unix.go b/transport/unix.go index 1dd239e..20c9c48 100644 --- a/transport/unix.go +++ b/transport/unix.go @@ -45,6 +45,7 @@ func UnixSocketTransport(sock string, opts ...ConnectionOption) (*Transport, err c: &http.Client{ Transport: t, }, - dial: dial, + dial: dial, + transform: go120Dot6HostTransform(sock), }, nil } From 356be0054d8d2950167b3a6b775509f9df54695d Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Thu, 13 Jul 2023 16:06:52 +0000 Subject: [PATCH 2/2] Fix err return check to use defer This was supposed to happen in a defer. Otherwise `retErr` is always nil. Signed-off-by: Brian Goff --- transport/transport.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/transport/transport.go b/transport/transport.go index 3100a27..d084086 100644 --- a/transport/transport.go +++ b/transport/transport.go @@ -94,9 +94,11 @@ func (t *Transport) DoRaw(ctx context.Context, method, uri string, opts ...Reque } cc := httputil.NewClientConn(conn, nil) - if retErr != nil { - cc.Close() - } + defer func() { + if retErr != nil { + cc.Close() + } + }() resp, err := cc.Do(req) if err != httputil.ErrPersistEOF {