Documentation
¶
Index ¶
- Variables
- func BlockedIP(ip netip.Addr) bool
- func GuardedDialContext(base *net.Dialer) func(ctx context.Context, network, addr string) (net.Conn, error)
- func GuardedDialWith(resolve func(ctx context.Context, network, host string) ([]netip.Addr, error), ...) func(ctx context.Context, network, addr string) (net.Conn, error)
- func ValidateHost(host string) error
- func ValidateURL(raw string) error
- type BlockedAddressError
- type HostValidator
- type LookupFunc
Constants ¶
This section is empty.
Variables ¶
var ( // ErrEmptyHost: the host is empty or blank. ErrEmptyHost = errors.New("empty host") // ErrUnresolvable: the host name did not resolve to an address. ErrUnresolvable = errors.New("host name could not be resolved") // ErrHostNotAllowed: the host is, or resolves to, a blocked address // (see BlockedIP). ErrHostNotAllowed = errors.New("destination not allowed") // ErrInvalidURL: the URL does not parse. ErrInvalidURL = errors.New("invalid URL") // ErrURLScheme: the URL scheme is neither http nor https. ErrURLScheme = errors.New("URL scheme must be http or https") // ErrURLNoHost: the URL has no host. ErrURLNoHost = errors.New("URL has no host") )
Errors of the pre-flight checks. Their texts are fixed: they never contain the checked host or URL, a resolved address or resolver details, so a caller may return them to the client that submitted the value.
var ErrBlockedAddress = errors.New("dial refused: address resolves to a blocked range")
ErrBlockedAddress is returned by the guarded dialer when a resolved address is blocked.
Functions ¶
func BlockedIP ¶
BlockedIP reports whether an outbound connection to ip must be refused to prevent SSRF: loopback, link-local (incl. the cloud metadata endpoint), multicast, and unspecified addresses are blocked. Private RFC-1918 ranges are intentionally allowed (legitimate private clusters live there).
func GuardedDialContext ¶
func GuardedDialContext(base *net.Dialer) func(ctx context.Context, network, addr string) (net.Conn, error)
GuardedDialContext returns a DialContext that resolves the host, refuses the dial if ANY resolved address is blocked (matching the validation-time guard's all-addresses policy), and connects to the exact validated IPs in order to close the resolve->dial TOCTOU window (DNS rebinding) while preserving multi-address failover for HA hosts. base may be nil (a default dialer with a sane timeout is used).
After confirming that no resolved address is blocked, each IP is tried in the order returned by the resolver; the first successful connection is returned. If every IP fails, the last dial error is returned (wrapped). The hostname is never re-resolved between attempts so the TOCTOU guarantee is preserved.
func GuardedDialWith ¶ added in v1.3.0
func GuardedDialWith( resolve func(ctx context.Context, network, host string) ([]netip.Addr, error), dialOne func(ctx context.Context, network, addr string) (net.Conn, error), ) func(ctx context.Context, network, addr string) (net.Conn, error)
GuardedDialWith is GuardedDialContext with an injectable resolver and per-IP dial function. Tests in other packages use it to point a guarded client at a local fake broker: the resolver maps a test host to an allowed address and dialOne redirects that address. The SSRF rules still apply to every resolved address, so a blocked address is refused before dialOne runs.
func ValidateHost ¶
ValidateHost is HostValidator.Host for a single host, resolved with net.DefaultResolver.
func ValidateURL ¶
ValidateURL is HostValidator.URL for a single URL, resolved with net.DefaultResolver.
Types ¶
type BlockedAddressError ¶ added in v1.3.0
type BlockedAddressError struct {
// Addr is the host:port the dial was asked for.
Addr string
// Host is the host part of Addr, as given (name or IP literal).
Host string
// IP is the first resolved address that is blocked, as resolved.
IP netip.Addr
}
BlockedAddressError is the error the guarded dialer returns when a resolved address is blocked. It unwraps to ErrBlockedAddress, so errors.Is keeps working, and carries the refused dial target for callers that report it.
func (*BlockedAddressError) Error ¶ added in v1.3.0
func (e *BlockedAddressError) Error() string
Error keeps the text of the former wrapped ErrBlockedAddress byte for byte.
func (*BlockedAddressError) Unwrap ¶ added in v1.3.0
func (e *BlockedAddressError) Unwrap() error
Unwrap makes errors.Is(err, ErrBlockedAddress) true.
type HostValidator ¶ added in v1.3.0
type HostValidator struct {
// contains filtered or unexported fields
}
HostValidator runs the pre-flight checks of ValidateHost and ValidateURL for one request. It keeps the result per host, so the definitions of a request that name the same host several times cost one lookup. It is safe for concurrent use; checks run one at a time.
These checks turn obviously unsafe destinations into a validation error before any connection is attempted. They are not the enforcement point: DNS can change between the check and the dial, so outbound connections must still go through GuardedDialContext.
func NewHostValidator ¶ added in v1.3.0
func NewHostValidator(lookup LookupFunc) *HostValidator
NewHostValidator returns a HostValidator that resolves host names with lookup, or with net.DefaultResolver when lookup is nil.