Skip to content

Commit

Permalink
reverseproxy: Dynamic ServerName for TLS upstreams (#4836)
Browse files Browse the repository at this point in the history
* 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: 3c9806c

Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
  • Loading branch information
kresike and mholt committed Jun 15, 2022
1 parent f9b42c3 commit c82fe91
Showing 1 changed file with 39 additions and 2 deletions.
41 changes: 39 additions & 2 deletions modules/caddyhttp/reverseproxy/httptransport.go
Expand Up @@ -25,6 +25,7 @@ import (
"net/http"
"os"
"reflect"
"strings"
"time"

"github.com/caddyserver/caddy/v2"
Expand Down Expand Up @@ -242,17 +243,53 @@ 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
if req.URL.Scheme == "http" && h.h2cTransport != nil {
return h.h2cTransport.RoundTrip(req)
}

return h.Transport.RoundTrip(req)
return transport.Transport.RoundTrip(req)
}

// SetScheme ensures that the outbound request req
Expand Down

0 comments on commit c82fe91

Please sign in to comment.