Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ modules:
# Whether to enable HTTP2.
[ enable_http2: <bool> | default: true ]

# Whether to enable HTTP3.
# Note: When enable_http3 is true, valid_http_versions must not include HTTP/2.0
# as HTTP/3 and HTTP/2 cannot be used together. Additionally, when enable_http3
# is true, enable_http2 must be set to false.
[ enable_http3: <bool> | default: false ]

# The IP protocol of the HTTP probe (ip4, ip6).
[ preferred_ip_protocol: <string> | default = "ip6" ]
[ ip_protocol_fallback: <boolean> | default = true ]
Expand Down
7 changes: 7 additions & 0 deletions blackbox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,10 @@ modules:
timeout: 5s
icmp:
ttl: 5
http_3xx:
prober: http
http:
preferred_ip_protocol: "ip4"
enable_http3: true
enable_http2: false
Comment thread
sebastianfeliciano marked this conversation as resolved.
valid_http_versions: ["HTTP/3.0"]
28 changes: 28 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ func (sc *SafeConfig) ReloadConfig(confFile string, logger *slog.Logger) (err er
logger.Warn("no_follow_redirects is deprecated and will be removed in the next release. It is replaced by follow_redirects.", "module", name)
}
}

// Warn if HTTP/3 is enabled - it requires HTTPS targets
if module.HTTP.UseHTTP3 && logger != nil {
logger.Warn("HTTP/3 is enabled for this module. HTTP targets will be automatically converted to HTTPS during probing. Consider using HTTPS targets directly in your configuration.", "module", name)
}
}

sc.Lock()
Expand Down Expand Up @@ -291,6 +296,7 @@ type HTTPProbe struct {
HTTPClientConfig config.HTTPClientConfig `yaml:"http_client_config,inline"`
Compression string `yaml:"compression,omitempty"`
BodySizeLimit units.Base2Bytes `yaml:"body_size_limit,omitempty"`
UseHTTP3 bool `yaml:"enable_http3,omitempty"`
}

type GRPCProbe struct {
Expand Down Expand Up @@ -419,6 +425,28 @@ func (s *HTTPProbe) UnmarshalYAML(unmarshal func(interface{}) error) error {
}
}

if !s.UseHTTP3 {
for _, version := range s.ValidHTTPVersions {
if version == "HTTP/3.0" {
return errors.New("HTTP/3 cannot be used as a valid HTTP version when enable_http3 is false")
Comment thread
sebastianfeliciano marked this conversation as resolved.
}
}
}

if s.UseHTTP3 {
// When HTTP/3 is enabled, HTTP/2.0 and HTTP/1.1 must not be in valid_http_versions
for _, version := range s.ValidHTTPVersions {
if version == "HTTP/2.0" || version == "HTTP/1.1" {
return errors.New("HTTP/3 and HTTP/2.0/1.1 cannot be used together - only HTTP/3.0 is allowed when enable_http3 is true")
}
}

// When HTTP/3 is enabled, HTTP/2 must be explicitly disabled
if s.HTTPClientConfig.EnableHTTP2 {
return errors.New("when enable_http3 is true, enable_http2 must be set to false")
}
}

return nil
}

Expand Down
16 changes: 16 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ func TestLoadBadConfigs(t *testing.T) {
input: "testdata/invalid-http-request-compression-reject-all-encodings.yml",
want: `error parsing config file: invalid configuration "Accept-Encoding: *;q=0.0", "compression: gzip"`,
},
{
input: "testdata/invalid-http-http3-http2.yml",
want: "error parsing config file: HTTP/3 and HTTP/2.0/1.1 cannot be used together - only HTTP/3.0 is allowed when enable_http3 is true",
},
{
input: "testdata/invalid-no-versions-http3-enabled.yml",
want: "error parsing config file: when enable_http3 is true, enable_http2 must be set to false",
},
{
input: "testdata/invalid-http-http3-http2-version.yml",
want: "error parsing config file: HTTP/3 and HTTP/2.0/1.1 cannot be used together - only HTTP/3.0 is allowed when enable_http3 is true",
},
{
input: "testdata/invalid-http-http3-http2-enabled.yml",
want: "error parsing config file: when enable_http3 is true, enable_http2 must be set to false",
},
{
input: "testdata/invalid-icmp-ttl.yml",
want: "error parsing config file: \"ttl\" cannot be negative",
Expand Down
9 changes: 9 additions & 0 deletions config/testdata/invalid-http-http3-http2-enabled.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
modules:
http_headers:
prober: http
timeout: 5s
http:
enable_http3: true
enable_http2: true
valid_http_versions: ["HTTP/3.0"]
preferred_ip_protocol: "ip4"
9 changes: 9 additions & 0 deletions config/testdata/invalid-http-http3-http2-version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
modules:
http_headers:
prober: http
timeout: 5s
http:
enable_http3: true
enable_http2: false
valid_http_versions: ["HTTP/1.1", "HTTP/2.0", "HTTP/3.0"]
preferred_ip_protocol: "ip4"
9 changes: 9 additions & 0 deletions config/testdata/invalid-http-http3-http2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
modules:
http_headers:
prober: http
timeout: 5s
http:
enable_http3: true
enable_http2: true
valid_http_versions: ["HTTP/1.1", "HTTP/2.0", "HTTP/3.0"]
preferred_ip_protocol: "ip4"
7 changes: 7 additions & 0 deletions config/testdata/invalid-no-versions-http3-enabled.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
modules:
http_headers:
prober: http
timeout: 5s
http:
enable_http3: true
preferred_ip_protocol: "ip4"
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ require (
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
go.uber.org/mock v0.5.0 // indirect
)

require (
cel.dev/expr v0.23.1 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
Expand All @@ -30,6 +38,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/quic-go v0.52.0
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
Expand Down
21 changes: 21 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -21,15 +24,20 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY=
github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
Expand All @@ -50,6 +58,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
Expand All @@ -62,13 +74,18 @@ github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHk
github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
Expand All @@ -87,6 +104,8 @@ go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5J
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
Expand All @@ -99,6 +118,7 @@ golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
Expand All @@ -119,5 +139,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
76 changes: 62 additions & 14 deletions prober/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
pconfig "github.com/prometheus/common/config"
"github.com/prometheus/common/version"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3"
"golang.org/x/net/publicsuffix"

"github.com/prometheus/blackbox_exporter/config"
Expand Down Expand Up @@ -205,7 +207,6 @@ func newTransport(rt, noServerName http.RoundTripper, logger *slog.Logger) *tran
// RoundTrip switches to a new trace, then runs embedded RoundTripper.
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
t.logger.Info("Making HTTP request", "url", req.URL.String(), "host", req.Host)

trace := &roundTripTrace{}
if req.URL.Scheme == "https" {
trace.tls = true
Expand All @@ -221,7 +222,12 @@ func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
// This is a redirect to something other than the initial host,
// so TLS ServerName should not be set.
t.logger.Info("Address does not match first address, not sending TLS ServerName", "first", t.firstHost, "address", req.URL.Host)
return t.NoServerNameTransport.RoundTrip(req)
// For HTTP/3, NoServerNameTransport might be nil as we don't create a serverless transport
if t.NoServerNameTransport != nil {
return t.NoServerNameTransport.RoundTrip(req)
}
// If NoServerNameTransport is nil, fall back to the normal Transport
t.logger.Info("No serverless transport available, using standard transport")
}

return t.Transport.RoundTrip(req)
Expand Down Expand Up @@ -380,6 +386,12 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr
target = "http://" + target
}

// For HTTP/3, ensure HTTPS is used
if httpConfig.UseHTTP3 && strings.HasPrefix(target, "http://") {
Comment thread
sebastianfeliciano marked this conversation as resolved.
target = strings.Replace(target, "http://", "https://", 1)
logger.Warn("Converting HTTP to HTTPS for HTTP/3 compatibility", "original_target", strings.Replace(target, "https://", "http://", 1), "converted_target", target)
}

targetURL, err := url.Parse(target)
if err != nil {
logger.Error("Could not parse target URL", "err", err)
Expand Down Expand Up @@ -415,17 +427,50 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr
}
}
}
client, err := pconfig.NewClientFromConfig(httpClientConfig, "http_probe", pconfig.WithKeepAlivesDisabled())
if err != nil {
logger.Error("Error generating HTTP client", "err", err)
return false
}
var client *http.Client
var noServerName http.RoundTripper

httpClientConfig.TLSConfig.ServerName = ""
noServerName, err := pconfig.NewRoundTripperFromConfig(httpClientConfig, "http_probe", pconfig.WithKeepAlivesDisabled())
if err != nil {
logger.Error("Error generating HTTP client without ServerName", "err", err)
return false
if httpConfig.UseHTTP3 {
// For HTTP/3, create TLS config from httpClientConfig but ensure TLS 1.3
tlsConfig, err := pconfig.NewTLSConfig(&httpClientConfig.TLSConfig)
if err != nil {
logger.Error("Error creating TLS config for HTTP/3", "err", err)
return false
}

// HTTP/3 requires TLS 1.3 minimum
if tlsConfig.MinVersion < tls.VersionTLS13 {
tlsConfig.MinVersion = tls.VersionTLS13
}

http3Transport := &http3.Transport{
TLSClientConfig: tlsConfig,
QUICConfig: &quic.Config{},
}
defer http3Transport.Close()

client = &http.Client{
Transport: http3Transport,
}

} else {
// For standard HTTP/HTTPS, create client from config
client, err = pconfig.NewClientFromConfig(httpClientConfig, "http_probe", pconfig.WithKeepAlivesDisabled())
if err != nil {
logger.Error("Error generating HTTP client", "err", err)
return false
}

// Create a second transport without ServerName for redirects to different hosts
// See https://github.com/quic-go/quic-go/issues/4049 for why we don't do this for HTTP/3
serverNamelessConfig := httpClientConfig
serverNamelessConfig.TLSConfig.ServerName = ""

noServerName, err = pconfig.NewRoundTripperFromConfig(serverNamelessConfig, "http_probe", pconfig.WithKeepAlivesDisabled())
if err != nil {
logger.Error("Error generating HTTP client without ServerName", "err", err)
return false
}
}

jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
Expand All @@ -438,6 +483,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr
// Inject transport that tracks traces for each redirect,
// and does not set TLS ServerNames on redirect if needed.
tt := newTransport(client.Transport, noServerName, logger)

client.Transport = tt

client.CheckRedirect = func(r *http.Request, via []*http.Request) error {
Expand All @@ -455,8 +501,8 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr
}

origHost := targetURL.Host
if ip != nil {
// Replace the host field in the URL with the IP we resolved.
if ip != nil && !httpConfig.UseHTTP3 {
// Replace the host field in the URL with the IP we resolved if not using HTTP/3.
if targetPort == "" {
if strings.Contains(ip.String(), ":") {
targetURL.Host = "[" + ip.String() + "]"
Expand Down Expand Up @@ -493,6 +539,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr
return
}
request.Host = origHost

request = request.WithContext(ctx)

for key, value := range httpConfig.Headers {
Expand All @@ -519,6 +566,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr
TLSHandshakeStart: tt.TLSHandshakeStart,
TLSHandshakeDone: tt.TLSHandshakeDone,
}

request = request.WithContext(httptrace.WithClientTrace(request.Context(), trace))

for _, lv := range []string{"connect", "tls", "processing", "transfer"} {
Expand Down
Loading