From 584144100524277829f26219baaab29a53b8134f Mon Sep 17 00:00:00 2001 From: Kevin Pollet Date: Mon, 16 Sep 2024 11:10:04 +0200 Subject: [PATCH] Cleanup Connection headers before passing the middleware chain Co-authored-by: Romain --- .../reference/static-configuration/cli-ref.md | 3 + .../reference/static-configuration/env-ref.md | 3 + .../reference/static-configuration/file.toml | 1 + .../reference/static-configuration/file.yaml | 3 + docs/content/routing/entrypoints.md | 34 +++ .../connection_hop_by_hop_headers.toml | 37 +++ integration/headers_test.go | 53 ++++ pkg/config/static/entrypoints.go | 1 + .../connectionheader.go | 2 +- .../connectionheader_test.go | 2 +- pkg/middlewares/auth/forward.go | 3 +- .../forwardedheaders/forwarded_header.go | 75 ++++- .../forwardedheaders/forwarded_header_test.go | 282 +++++++++++++++++- pkg/middlewares/headers/headers.go | 6 +- pkg/server/server_entrypoint_tcp.go | 1 + 15 files changed, 475 insertions(+), 31 deletions(-) create mode 100644 integration/fixtures/headers/connection_hop_by_hop_headers.toml rename pkg/middlewares/{connectionheader => auth}/connectionheader.go (97%) rename pkg/middlewares/{connectionheader => auth}/connectionheader_test.go (98%) diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md index 362146ac0..540ff8ad0 100644 --- a/docs/content/reference/static-configuration/cli-ref.md +++ b/docs/content/reference/static-configuration/cli-ref.md @@ -111,6 +111,9 @@ Entry point address. `--entrypoints..allowacmebypass`: Enables handling of ACME TLS and HTTP challenges with custom routers. (Default: ```false```) +`--entrypoints..forwardedheaders.connection`: +List of Connection headers that are allowed to pass through the middleware chain before being removed. + `--entrypoints..forwardedheaders.insecure`: Trust all forwarded headers. (Default: ```false```) diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md index 6ca27db89..173c18c3e 100644 --- a/docs/content/reference/static-configuration/env-ref.md +++ b/docs/content/reference/static-configuration/env-ref.md @@ -111,6 +111,9 @@ Entry point address. `TRAEFIK_ENTRYPOINTS__ALLOWACMEBYPASS`: Enables handling of ACME TLS and HTTP challenges with custom routers. (Default: ```false```) +`TRAEFIK_ENTRYPOINTS__FORWARDEDHEADERS_CONNECTION`: +List of Connection headers that are allowed to pass through the middleware chain before being removed. + `TRAEFIK_ENTRYPOINTS__FORWARDEDHEADERS_INSECURE`: Trust all forwarded headers. (Default: ```false```) diff --git a/docs/content/reference/static-configuration/file.toml b/docs/content/reference/static-configuration/file.toml index 8f6f9510e..89844adfe 100644 --- a/docs/content/reference/static-configuration/file.toml +++ b/docs/content/reference/static-configuration/file.toml @@ -33,6 +33,7 @@ [entryPoints.EntryPoint0.forwardedHeaders] insecure = true trustedIPs = ["foobar", "foobar"] + connection = ["foobar", "foobar"] [entryPoints.EntryPoint0.http] middlewares = ["foobar", "foobar"] encodeQuerySemicolons = true diff --git a/docs/content/reference/static-configuration/file.yaml b/docs/content/reference/static-configuration/file.yaml index 09e66b545..38541da46 100644 --- a/docs/content/reference/static-configuration/file.yaml +++ b/docs/content/reference/static-configuration/file.yaml @@ -37,6 +37,9 @@ entryPoints: trustedIPs: - foobar - foobar + connection: + - foobar + - foobar http: redirections: entryPoint: diff --git a/docs/content/routing/entrypoints.md b/docs/content/routing/entrypoints.md index ca34161d2..b87e09b92 100644 --- a/docs/content/routing/entrypoints.md +++ b/docs/content/routing/entrypoints.md @@ -422,6 +422,40 @@ You can configure Traefik to trust the forwarded headers information (`X-Forward --entryPoints.web.forwardedHeaders.insecure ``` +??? info "`forwardedHeaders.connection`" + + As per RFC7230, Traefik respects the Connection options from the client request. + By doing so, it removes any header field(s) listed in the request Connection header and the Connection header field itself when empty. + The removal happens as soon as the request is handled by Traefik, + thus the removed headers are not available when the request passes through the middleware chain. + The `connection` option lists the Connection headers allowed to passthrough the middleware chain before their removal. + + ```yaml tab="File (YAML)" + ## Static configuration + entryPoints: + web: + address: ":80" + forwardedHeaders: + connection: + - foobar + ``` + + ```toml tab="File (TOML)" + ## Static configuration + [entryPoints] + [entryPoints.web] + address = ":80" + + [entryPoints.web.forwardedHeaders] + connection = ["foobar"] + ``` + + ```bash tab="CLI" + ## Static configuration + --entryPoints.web.address=:80 + --entryPoints.web.forwardedHeaders.connection=foobar + ``` + ### Transport #### `respondingTimeouts` diff --git a/integration/fixtures/headers/connection_hop_by_hop_headers.toml b/integration/fixtures/headers/connection_hop_by_hop_headers.toml new file mode 100644 index 000000000..091e1995c --- /dev/null +++ b/integration/fixtures/headers/connection_hop_by_hop_headers.toml @@ -0,0 +1,37 @@ +[global] + checkNewVersion = false + sendAnonymousUsage = false + +[log] + level = "DEBUG" + +# Limiting the Logs to Specific Fields +[accessLog] + format = "json" + filePath = "access.log" + + [accessLog.fields.headers.names] + "Foo" = "keep" + "Bar" = "keep" + +[entryPoints] + [entryPoints.web] + address = ":8000" + [entryPoints.web.forwardedHeaders] + insecure = true + connection = ["Foo"] + +[providers.file] + filename = "{{ .SelfFilename }}" + +## dynamic configuration ## + +[http.routers] + [http.routers.router1] + rule = "Host(`test.localhost`)" + service = "service1" + +[http.services] + [http.services.service1.loadBalancer] + [[http.services.service1.loadBalancer.servers]] + url = "http://127.0.0.1:9000" diff --git a/integration/headers_test.go b/integration/headers_test.go index 68522cc47..2b6c53be2 100644 --- a/integration/headers_test.go +++ b/integration/headers_test.go @@ -4,6 +4,7 @@ import ( "net" "net/http" "net/http/httptest" + "os" "testing" "time" @@ -20,6 +21,11 @@ func TestHeadersSuite(t *testing.T) { suite.Run(t, new(HeadersSuite)) } +func (s *HeadersSuite) TearDownTest() { + s.displayTraefikLogFile(traefikTestLogFile) + _ = os.Remove(traefikTestAccessLogFile) +} + func (s *HeadersSuite) TestSimpleConfiguration() { s.traefikCmd(withConfigFile("fixtures/headers/basic.toml")) @@ -62,6 +68,53 @@ func (s *HeadersSuite) TestReverseProxyHeaderRemoved() { require.NoError(s.T(), err) } +func (s *HeadersSuite) TestConnectionHopByHop() { + file := s.adaptFile("fixtures/headers/connection_hop_by_hop_headers.toml", struct{}{}) + s.traefikCmd(withConfigFile(file)) + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, found := r.Header["X-Forwarded-For"] + assert.True(s.T(), found) + xHost, found := r.Header["X-Forwarded-Host"] + assert.True(s.T(), found) + assert.Equal(s.T(), "localhost", xHost[0]) + + _, found = r.Header["Foo"] + assert.False(s.T(), found) + _, found = r.Header["Bar"] + assert.False(s.T(), found) + }) + + listener, err := net.Listen("tcp", "127.0.0.1:9000") + require.NoError(s.T(), err) + + ts := &httptest.Server{ + Listener: listener, + Config: &http.Server{Handler: handler}, + } + ts.Start() + defer ts.Close() + + req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) + require.NoError(s.T(), err) + req.Host = "test.localhost" + req.Header = http.Header{ + "Connection": {"Foo,Bar,X-Forwarded-For,X-Forwarded-Host"}, + "Foo": {"bar"}, + "Bar": {"foo"}, + "X-Forwarded-Host": {"localhost"}, + } + + err = try.Request(req, time.Second, try.StatusCodeIs(http.StatusOK)) + require.NoError(s.T(), err) + + accessLog, err := os.ReadFile(traefikTestAccessLogFile) + require.NoError(s.T(), err) + + assert.Contains(s.T(), string(accessLog), "\"request_Foo\":\"bar\"") + assert.NotContains(s.T(), string(accessLog), "\"request_Bar\":\"\"") +} + func (s *HeadersSuite) TestCorsResponses() { file := s.adaptFile("fixtures/headers/cors.toml", struct{}{}) s.traefikCmd(withConfigFile(file)) diff --git a/pkg/config/static/entrypoints.go b/pkg/config/static/entrypoints.go index 8bfbc59f1..27b9f7a0b 100644 --- a/pkg/config/static/entrypoints.go +++ b/pkg/config/static/entrypoints.go @@ -110,6 +110,7 @@ type TLSConfig struct { type ForwardedHeaders struct { Insecure bool `description:"Trust all forwarded headers." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"` TrustedIPs []string `description:"Trust only forwarded headers from selected IPs." json:"trustedIPs,omitempty" toml:"trustedIPs,omitempty" yaml:"trustedIPs,omitempty"` + Connection []string `description:"List of Connection headers that are allowed to pass through the middleware chain before being removed." json:"connection,omitempty" toml:"connection,omitempty" yaml:"connection,omitempty"` } // ProxyProtocol contains Proxy-Protocol configuration. diff --git a/pkg/middlewares/connectionheader/connectionheader.go b/pkg/middlewares/auth/connectionheader.go similarity index 97% rename from pkg/middlewares/connectionheader/connectionheader.go rename to pkg/middlewares/auth/connectionheader.go index b7a64910a..1cd1da81a 100644 --- a/pkg/middlewares/connectionheader/connectionheader.go +++ b/pkg/middlewares/auth/connectionheader.go @@ -1,4 +1,4 @@ -package connectionheader +package auth import ( "net/http" diff --git a/pkg/middlewares/connectionheader/connectionheader_test.go b/pkg/middlewares/auth/connectionheader_test.go similarity index 98% rename from pkg/middlewares/connectionheader/connectionheader_test.go rename to pkg/middlewares/auth/connectionheader_test.go index bd41d58d8..00d719ef0 100644 --- a/pkg/middlewares/connectionheader/connectionheader_test.go +++ b/pkg/middlewares/auth/connectionheader_test.go @@ -1,4 +1,4 @@ -package connectionheader +package auth import ( "net/http" diff --git a/pkg/middlewares/auth/forward.go b/pkg/middlewares/auth/forward.go index 70b3374ab..27d42973c 100644 --- a/pkg/middlewares/auth/forward.go +++ b/pkg/middlewares/auth/forward.go @@ -15,7 +15,6 @@ import ( "github.com/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/log" "github.com/traefik/traefik/v2/pkg/middlewares" - "github.com/traefik/traefik/v2/pkg/middlewares/connectionheader" "github.com/traefik/traefik/v2/pkg/tracing" "github.com/vulcand/oxy/v2/forward" "github.com/vulcand/oxy/v2/utils" @@ -90,7 +89,7 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu fa.authResponseHeadersRegex = re } - return connectionheader.Remover(fa), nil + return Remover(fa), nil } func (fa *forwardAuth) GetTracingInformation() (string, ext.SpanKindEnum) { diff --git a/pkg/middlewares/forwardedheaders/forwarded_header.go b/pkg/middlewares/forwardedheaders/forwarded_header.go index 19881ad74..6f715ccfb 100644 --- a/pkg/middlewares/forwardedheaders/forwarded_header.go +++ b/pkg/middlewares/forwardedheaders/forwarded_header.go @@ -3,10 +3,13 @@ package forwardedheaders import ( "net" "net/http" + "net/textproto" "os" + "slices" "strings" "github.com/traefik/traefik/v2/pkg/ip" + "golang.org/x/net/http/httpguts" ) const ( @@ -42,19 +45,20 @@ var xHeaders = []string{ // Unless insecure is set, // it first removes all the existing values for those headers if the remote address is not one of the trusted ones. type XForwarded struct { - insecure bool - trustedIps []string - ipChecker *ip.Checker - next http.Handler - hostname string + insecure bool + trustedIPs []string + connectionHeaders []string + ipChecker *ip.Checker + next http.Handler + hostname string } // NewXForwarded creates a new XForwarded. -func NewXForwarded(insecure bool, trustedIps []string, next http.Handler) (*XForwarded, error) { +func NewXForwarded(insecure bool, trustedIPs []string, connectionHeaders []string, next http.Handler) (*XForwarded, error) { var ipChecker *ip.Checker - if len(trustedIps) > 0 { + if len(trustedIPs) > 0 { var err error - ipChecker, err = ip.NewChecker(trustedIps) + ipChecker, err = ip.NewChecker(trustedIPs) if err != nil { return nil, err } @@ -66,11 +70,12 @@ func NewXForwarded(insecure bool, trustedIps []string, next http.Handler) (*XFor } return &XForwarded{ - insecure: insecure, - trustedIps: trustedIps, - ipChecker: ipChecker, - next: next, - hostname: hostname, + insecure: insecure, + trustedIPs: trustedIPs, + connectionHeaders: connectionHeaders, + ipChecker: ipChecker, + next: next, + hostname: hostname, }, nil } @@ -189,9 +194,53 @@ func (x *XForwarded) ServeHTTP(w http.ResponseWriter, r *http.Request) { x.rewrite(r) + x.removeConnectionHeaders(r) + x.next.ServeHTTP(w, r) } +func (x *XForwarded) removeConnectionHeaders(req *http.Request) { + var reqUpType string + if httpguts.HeaderValuesContainsToken(req.Header[connection], upgrade) { + reqUpType = unsafeHeader(req.Header).Get(upgrade) + } + + var connectionHopByHopHeaders []string + for _, f := range req.Header[connection] { + for _, sf := range strings.Split(f, ",") { + if sf = textproto.TrimString(sf); sf != "" { + // Connection header cannot dictate to remove X- headers managed by Traefik, + // as per rfc7230 https://datatracker.ietf.org/doc/html/rfc7230#section-6.1, + // A proxy or gateway MUST ... and then remove the Connection header field itself + // (or replace it with the intermediary's own connection options for the forwarded message). + if slices.Contains(xHeaders, sf) { + continue + } + + // Keep headers allowed through the middleware chain. + if slices.Contains(x.connectionHeaders, sf) { + connectionHopByHopHeaders = append(connectionHopByHopHeaders, sf) + continue + } + + // Apply Connection header option. + req.Header.Del(sf) + } + } + } + + if reqUpType != "" { + connectionHopByHopHeaders = append(connectionHopByHopHeaders, upgrade) + unsafeHeader(req.Header).Set(upgrade, reqUpType) + } + if len(connectionHopByHopHeaders) > 0 { + unsafeHeader(req.Header).Set(connection, strings.Join(connectionHopByHopHeaders, ",")) + return + } + + unsafeHeader(req.Header).Del(connection) +} + // unsafeHeader allows to manage Header values. // Must be used only when the header name is already a canonical key. type unsafeHeader map[string][]string diff --git a/pkg/middlewares/forwardedheaders/forwarded_header_test.go b/pkg/middlewares/forwardedheaders/forwarded_header_test.go index 8e1d10925..414fd5007 100644 --- a/pkg/middlewares/forwardedheaders/forwarded_header_test.go +++ b/pkg/middlewares/forwardedheaders/forwarded_header_test.go @@ -12,15 +12,16 @@ import ( func TestServeHTTP(t *testing.T) { testCases := []struct { - desc string - insecure bool - trustedIps []string - incomingHeaders map[string][]string - remoteAddr string - expectedHeaders map[string]string - tls bool - websocket bool - host string + desc string + insecure bool + trustedIps []string + connectionHeaders []string + incomingHeaders map[string][]string + remoteAddr string + expectedHeaders map[string]string + tls bool + websocket bool + host string }{ { desc: "all Empty", @@ -269,6 +270,196 @@ func TestServeHTTP(t *testing.T) { xForwardedServer: "foo.com:8080", }, }, + { + desc: "Untrusted: Connection header has no effect on X- forwarded headers", + insecure: false, + incomingHeaders: map[string][]string{ + connection: { + xForwardedProto, + xForwardedFor, + xForwardedURI, + xForwardedMethod, + xForwardedHost, + xForwardedPort, + xForwardedTLSClientCert, + xForwardedTLSClientCertInfo, + xRealIP, + }, + xForwardedProto: {"foo"}, + xForwardedFor: {"foo"}, + xForwardedURI: {"foo"}, + xForwardedMethod: {"foo"}, + xForwardedHost: {"foo"}, + xForwardedPort: {"foo"}, + xForwardedTLSClientCert: {"foo"}, + xForwardedTLSClientCertInfo: {"foo"}, + xRealIP: {"foo"}, + }, + expectedHeaders: map[string]string{ + xForwardedProto: "http", + xForwardedFor: "", + xForwardedURI: "", + xForwardedMethod: "", + xForwardedHost: "", + xForwardedPort: "80", + xForwardedTLSClientCert: "", + xForwardedTLSClientCertInfo: "", + xRealIP: "", + connection: "", + }, + }, + { + desc: "Trusted (insecure): Connection header has no effect on X- forwarded headers", + insecure: true, + incomingHeaders: map[string][]string{ + connection: { + xForwardedProto, + xForwardedFor, + xForwardedURI, + xForwardedMethod, + xForwardedHost, + xForwardedPort, + xForwardedTLSClientCert, + xForwardedTLSClientCertInfo, + xRealIP, + }, + xForwardedProto: {"foo"}, + xForwardedFor: {"foo"}, + xForwardedURI: {"foo"}, + xForwardedMethod: {"foo"}, + xForwardedHost: {"foo"}, + xForwardedPort: {"foo"}, + xForwardedTLSClientCert: {"foo"}, + xForwardedTLSClientCertInfo: {"foo"}, + xRealIP: {"foo"}, + }, + expectedHeaders: map[string]string{ + xForwardedProto: "foo", + xForwardedFor: "foo", + xForwardedURI: "foo", + xForwardedMethod: "foo", + xForwardedHost: "foo", + xForwardedPort: "foo", + xForwardedTLSClientCert: "foo", + xForwardedTLSClientCertInfo: "foo", + xRealIP: "foo", + connection: "", + }, + }, + { + desc: "Untrusted and Connection: Connection header has no effect on X- forwarded headers", + insecure: false, + connectionHeaders: []string{ + xForwardedProto, + xForwardedFor, + xForwardedURI, + xForwardedMethod, + xForwardedHost, + xForwardedPort, + xForwardedTLSClientCert, + xForwardedTLSClientCertInfo, + xRealIP, + }, + incomingHeaders: map[string][]string{ + connection: { + xForwardedProto, + xForwardedFor, + xForwardedURI, + xForwardedMethod, + xForwardedHost, + xForwardedPort, + xForwardedTLSClientCert, + xForwardedTLSClientCertInfo, + xRealIP, + }, + xForwardedProto: {"foo"}, + xForwardedFor: {"foo"}, + xForwardedURI: {"foo"}, + xForwardedMethod: {"foo"}, + xForwardedHost: {"foo"}, + xForwardedPort: {"foo"}, + xForwardedTLSClientCert: {"foo"}, + xForwardedTLSClientCertInfo: {"foo"}, + xRealIP: {"foo"}, + }, + expectedHeaders: map[string]string{ + xForwardedProto: "http", + xForwardedFor: "", + xForwardedURI: "", + xForwardedMethod: "", + xForwardedHost: "", + xForwardedPort: "80", + xForwardedTLSClientCert: "", + xForwardedTLSClientCertInfo: "", + xRealIP: "", + connection: "", + }, + }, + { + desc: "Trusted (insecure) and Connection: Connection header has no effect on X- forwarded headers", + insecure: true, + connectionHeaders: []string{ + xForwardedProto, + xForwardedFor, + xForwardedURI, + xForwardedMethod, + xForwardedHost, + xForwardedPort, + xForwardedTLSClientCert, + xForwardedTLSClientCertInfo, + xRealIP, + }, + incomingHeaders: map[string][]string{ + connection: { + xForwardedProto, + xForwardedFor, + xForwardedURI, + xForwardedMethod, + xForwardedHost, + xForwardedPort, + xForwardedTLSClientCert, + xForwardedTLSClientCertInfo, + xRealIP, + }, + xForwardedProto: {"foo"}, + xForwardedFor: {"foo"}, + xForwardedURI: {"foo"}, + xForwardedMethod: {"foo"}, + xForwardedHost: {"foo"}, + xForwardedPort: {"foo"}, + xForwardedTLSClientCert: {"foo"}, + xForwardedTLSClientCertInfo: {"foo"}, + xRealIP: {"foo"}, + }, + expectedHeaders: map[string]string{ + xForwardedProto: "foo", + xForwardedFor: "foo", + xForwardedURI: "foo", + xForwardedMethod: "foo", + xForwardedHost: "foo", + xForwardedPort: "foo", + xForwardedTLSClientCert: "foo", + xForwardedTLSClientCertInfo: "foo", + xRealIP: "foo", + connection: "", + }, + }, + { + desc: "Connection: one remove, and one passthrough header", + connectionHeaders: []string{ + "foo", + }, + incomingHeaders: map[string][]string{ + connection: { + "foo", + }, + "Foo": {"bar"}, + "Bar": {"foo"}, + }, + expectedHeaders: map[string]string{ + "Bar": "foo", + }, + }, } for _, test := range testCases { @@ -299,7 +490,7 @@ func TestServeHTTP(t *testing.T) { } } - m, err := NewXForwarded(test.insecure, test.trustedIps, + m, err := NewXForwarded(test.insecure, test.trustedIps, test.connectionHeaders, http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {})) require.NoError(t, err) @@ -382,3 +573,74 @@ func Test_isWebsocketRequest(t *testing.T) { }) } } + +func TestConnection(t *testing.T) { + testCases := []struct { + desc string + reqHeaders map[string]string + connectionHeaders []string + expected http.Header + }{ + { + desc: "simple remove", + reqHeaders: map[string]string{ + "Foo": "bar", + connection: "foo", + }, + expected: http.Header{}, + }, + { + desc: "remove and upgrade", + reqHeaders: map[string]string{ + upgrade: "test", + "Foo": "bar", + connection: "upgrade,foo", + }, + expected: http.Header{ + upgrade: []string{"test"}, + connection: []string{"Upgrade"}, + }, + }, + { + desc: "no remove", + reqHeaders: map[string]string{ + "Foo": "bar", + connection: "fii", + }, + expected: http.Header{ + "Foo": []string{"bar"}, + }, + }, + { + desc: "no remove because connection header pass through", + reqHeaders: map[string]string{ + "Foo": "bar", + connection: "Foo", + }, + connectionHeaders: []string{"Foo"}, + expected: http.Header{ + "Foo": []string{"bar"}, + connection: []string{"Foo"}, + }, + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + forwarded, err := NewXForwarded(true, nil, test.connectionHeaders, nil) + require.NoError(t, err) + + req := httptest.NewRequest(http.MethodGet, "https://localhost", nil) + + for k, v := range test.reqHeaders { + req.Header.Set(k, v) + } + + forwarded.removeConnectionHeaders(req) + + assert.Equal(t, test.expected, req.Header) + }) + } +} diff --git a/pkg/middlewares/headers/headers.go b/pkg/middlewares/headers/headers.go index 503944f24..5ed9f2807 100644 --- a/pkg/middlewares/headers/headers.go +++ b/pkg/middlewares/headers/headers.go @@ -10,7 +10,6 @@ import ( "github.com/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/log" "github.com/traefik/traefik/v2/pkg/middlewares" - "github.com/traefik/traefik/v2/pkg/middlewares/connectionheader" "github.com/traefik/traefik/v2/pkg/tracing" ) @@ -69,12 +68,11 @@ func New(ctx context.Context, next http.Handler, cfg dynamic.Headers, name strin if hasCustomHeaders || hasCorsHeaders { logger.Debugf("Setting up customHeaders/Cors from %v", cfg) - h, err := NewHeader(nextHandler, cfg) + var err error + handler, err = NewHeader(nextHandler, cfg) if err != nil { return nil, err } - - handler = connectionheader.Remover(h) } return &headers{ diff --git a/pkg/server/server_entrypoint_tcp.go b/pkg/server/server_entrypoint_tcp.go index 6e30de331..5cd6cbb49 100644 --- a/pkg/server/server_entrypoint_tcp.go +++ b/pkg/server/server_entrypoint_tcp.go @@ -565,6 +565,7 @@ func createHTTPServer(ctx context.Context, ln net.Listener, configuration *stati handler, err = forwardedheaders.NewXForwarded( configuration.ForwardedHeaders.Insecure, configuration.ForwardedHeaders.TrustedIPs, + configuration.ForwardedHeaders.Connection, next) if err != nil { return nil, err