@marcel91200 / caddy Mirror · read-only / commits / aa3d20be
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 12, 00:45 UTC

reverseproxy: Use DialTLSContext if ServerName has placeholder (#6955)

Co-authored-by: Matt Holt <mholt@users.noreply.github.com>

WeidiDeng committed Apr 28, 2025 at 23:14 UTC aa3d20be3ee451af9465470a28937690104e9422
1 file changed +32 -38
modules/caddyhttp/reverseproxy/httptransport.go
+32 -38
@@ -382,6 +382,36 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
382 if err != nil {
383 return nil, fmt.Errorf("making TLS client config: %v", err)
384 }
385 +
386 + // servername has a placeholder, so we need to replace it
387 + if strings.Contains(h.TLS.ServerName, "{") {
388 + rt.DialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
389 + // reuses the dialer from above to establish a plaintext connection
390 + conn, err := dialContext(ctx, network, addr)
391 + if err != nil {
392 + return nil, err
393 + }
394 +
395 + // but add our own handshake logic
396 + repl := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
397 + tlsConfig := rt.TLSClientConfig.Clone()
398 + tlsConfig.ServerName = repl.ReplaceAll(tlsConfig.ServerName, "")
399 + tlsConn := tls.Client(conn, tlsConfig)
400 +
401 + // complete the handshake before returning the connection
402 + if rt.TLSHandshakeTimeout != 0 {
403 + var cancel context.CancelFunc
404 + ctx, cancel = context.WithTimeout(ctx, rt.TLSHandshakeTimeout)
405 + defer cancel()
406 + }
407 + err = tlsConn.HandshakeContext(ctx)
408 + if err != nil {
409 + _ = tlsConn.Close()
410 + return nil, err
411 + }
412 + return tlsConn, nil
413 + }
414 + }
415 }
416
417 if h.KeepAlive != nil {
@@ -453,45 +483,9 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
483 return rt, nil
484 }
485
456 -// replaceTLSServername checks TLS servername to see if it needs replacing
457 -// if it does need replacing, it creates a new cloned HTTPTransport object to avoid any races
458 -// and does the replacing of the TLS servername on that and returns the new object
459 -// if no replacement is necessary it returns the original
460 -func (h *HTTPTransport) replaceTLSServername(repl *caddy.Replacer) *HTTPTransport {
461 - // check whether we have TLS and need to replace the servername in the TLSClientConfig
462 - if h.TLSEnabled() && strings.Contains(h.TLS.ServerName, "{") {
463 - // make a new h, "copy" the parts we don't need to touch, add a new *tls.Config and replace servername
464 - newtransport := &HTTPTransport{
465 - Resolver: h.Resolver,
466 - TLS: h.TLS,
467 - KeepAlive: h.KeepAlive,
468 - Compression: h.Compression,
469 - MaxConnsPerHost: h.MaxConnsPerHost,
470 - DialTimeout: h.DialTimeout,
471 - FallbackDelay: h.FallbackDelay,
472 - ResponseHeaderTimeout: h.ResponseHeaderTimeout,
473 - ExpectContinueTimeout: h.ExpectContinueTimeout,
474 - MaxResponseHeaderSize: h.MaxResponseHeaderSize,
475 - WriteBufferSize: h.WriteBufferSize,
476 - ReadBufferSize: h.ReadBufferSize,
477 - Versions: h.Versions,
478 - Transport: h.Transport.Clone(),
479 - h2cTransport: h.h2cTransport,
480 - }
481 - newtransport.Transport.TLSClientConfig.ServerName = repl.ReplaceAll(newtransport.Transport.TLSClientConfig.ServerName, "")
482 - return newtransport
483 - }
484 -
485 - return h
486 -}
487 -
486 // RoundTrip implements http.RoundTripper.
487 func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
490 - // Try to replace TLS servername if needed
491 - repl := req.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
492 - transport := h.replaceTLSServername(repl)
493 -
494 - transport.SetScheme(req)
488 + h.SetScheme(req)
489
490 // use HTTP/3 if enabled (TODO: This is EXPERIMENTAL)
491 if h.h3Transport != nil {
@@ -507,7 +501,7 @@ func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
501 return h.h2cTransport.RoundTrip(req)
502 }
503
510 - return transport.Transport.RoundTrip(req)
504 + return h.Transport.RoundTrip(req)
505 }
506
507 // SetScheme ensures that the outbound request req