diff options
author | Kiss Károly Pál <kiss.karoly.pal@gmail.com> | 2022-06-15 05:53:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-14 21:53:05 -0600 |
commit | c82fe91104efbbe62826510579ea57fd54c55f8c (patch) | |
tree | 2e9acfb95be15b3c215c6180ea589b3d6c18c4b4 | |
parent | f9b42c37723ba6fbbfc31c61119fc42963770ce9 (diff) |
reverseproxy: Dynamic ServerName for TLS upstreams (#4836)
* Make reverse proxy TLS server name replaceable for SNI upstreams.
* Reverted previous TLS server name replacement, and implemented thread safe version.
* Move TLS servername replacement into it's own function
* Moved SNI servername replacement into httptransport.
* Solve issue when dynamic upstreams use wrong protocol upstream.
* Revert previous commit.
Old commit was: Solve issue when dynamic upstreams use wrong protocol upstream.
Id: 3c9806ccb63e66bdcac8e1ed4520c9d135cb011d
Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
-rw-r--r-- | modules/caddyhttp/reverseproxy/httptransport.go | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/modules/caddyhttp/reverseproxy/httptransport.go b/modules/caddyhttp/reverseproxy/httptransport.go index 8bce580..eefc04a 100644 --- a/modules/caddyhttp/reverseproxy/httptransport.go +++ b/modules/caddyhttp/reverseproxy/httptransport.go @@ -25,6 +25,7 @@ import ( "net/http" "os" "reflect" + "strings" "time" "github.com/caddyserver/caddy/v2" @@ -242,9 +243,45 @@ func (h *HTTPTransport) NewTransport(ctx caddy.Context) (*http.Transport, error) return rt, nil } +// replaceTLSServername checks TLS servername to see if it needs replacing +// if it does need replacing, it creates a new cloned HTTPTransport object to avoid any races +// and does the replacing of the TLS servername on that and returns the new object +// if no replacement is necessary it returns the original +func (h *HTTPTransport) replaceTLSServername(repl *caddy.Replacer) *HTTPTransport { + // check whether we have TLS and need to replace the servername in the TLSClientConfig + if h.TLSEnabled() && strings.Contains(h.TLS.ServerName, "{") { + // make a new h, "copy" the parts we don't need to touch, add a new *tls.Config and replace servername + newtransport := &HTTPTransport{ + Resolver: h.Resolver, + TLS: h.TLS, + KeepAlive: h.KeepAlive, + Compression: h.Compression, + MaxConnsPerHost: h.MaxConnsPerHost, + DialTimeout: h.DialTimeout, + FallbackDelay: h.FallbackDelay, + ResponseHeaderTimeout: h.ResponseHeaderTimeout, + ExpectContinueTimeout: h.ExpectContinueTimeout, + MaxResponseHeaderSize: h.MaxResponseHeaderSize, + WriteBufferSize: h.WriteBufferSize, + ReadBufferSize: h.ReadBufferSize, + Versions: h.Versions, + Transport: h.Transport.Clone(), + h2cTransport: h.h2cTransport, + } + newtransport.Transport.TLSClientConfig.ServerName = repl.ReplaceAll(newtransport.Transport.TLSClientConfig.ServerName, "") + return newtransport + } + + return h +} + // RoundTrip implements http.RoundTripper. func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) { - h.SetScheme(req) + // Try to replace TLS servername if needed + repl := req.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) + transport := h.replaceTLSServername(repl) + + transport.SetScheme(req) // if H2C ("HTTP/2 over cleartext") is enabled and the upstream request is // HTTP without TLS, use the alternate H2C-capable transport instead @@ -252,7 +289,7 @@ func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) { return h.h2cTransport.RoundTrip(req) } - return h.Transport.RoundTrip(req) + return transport.Transport.RoundTrip(req) } // SetScheme ensures that the outbound request req |