mirror of
https://github.com/portainer/portainer.git
synced 2026-06-23 04:30:16 +00:00
54 lines
1.7 KiB
Go
54 lines
1.7 KiB
Go
package ssrf
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"net/http"
|
|
)
|
|
|
|
// NewTransport creates an SSRF-protected transport for user-influenced destinations.
|
|
// It clones http.DefaultTransport as its base (inheriting pool and timeout defaults)
|
|
// and applies the global SSRF dial-context filter so mode changes take effect without
|
|
// restarting. tlsConfig may be nil to preserve standard TLS behavior (system CAs).
|
|
func NewTransport(tlsConfig *tls.Config) *http.Transport {
|
|
base := http.DefaultTransport.(*http.Transport).Clone()
|
|
base.TLSClientConfig = tlsConfig
|
|
applySSRF(base)
|
|
|
|
return base
|
|
}
|
|
|
|
// NewInternalTransport creates a plain transport for destinations chosen by Portainer,
|
|
// not by the user (Docker socket proxy, Chisel tunnels, in-cluster Kubernetes API).
|
|
// It clones http.DefaultTransport as its base. tlsConfig may be nil.
|
|
// Using this function instead of NewTransport makes the exemption explicit and
|
|
// satisfies the ruleguard lint rule.
|
|
func NewInternalTransport(tlsConfig *tls.Config) *http.Transport {
|
|
base := http.DefaultTransport.(*http.Transport).Clone()
|
|
base.TLSClientConfig = tlsConfig
|
|
|
|
return base
|
|
}
|
|
|
|
// WrapDefaultTransport replaces http.DefaultTransport with an SSRF-protected version.
|
|
// Must be called after Configure. Returns false if DefaultTransport is not an *http.Transport.
|
|
func WrapDefaultTransport() bool {
|
|
dt, ok := http.DefaultTransport.(*http.Transport)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
cloned := dt.Clone()
|
|
applySSRF(cloned)
|
|
http.DefaultTransport = cloned
|
|
|
|
return true
|
|
}
|
|
|
|
// applySSRF sets the SSRF-filtering DialContext on t when the global dialer is active.
|
|
func applySSRF(t *http.Transport) {
|
|
d := globalDialer.Load()
|
|
if d != nil {
|
|
t.DialContext = d.DialContext
|
|
}
|
|
}
|