Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
Go
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677package hostutil
import ( "fmt" "net" "net/http" "net/url" "syscall"
"github.com/bluesky-social/indigo/util/ssrf" "time")
// safeDialer rejects dials to non-public addresses. the Control hook runs before// connect, so it also covers rebinding and redirects, and inherits indigo's// maintained blocklist (6to4, nat64 and the rest). disabled in dev.func safeDialer(dev bool) *net.Dialer { d := &net.Dialer{ Timeout: 10 * time.Second, KeepAlive: 30 * time.Second, } if dev { return d } d.Control = func(_, address string, _ syscall.RawConn) error { host, _, err := net.SplitHostPort(address) if err != nil { return fmt.Errorf("invalid dial address %q: %w", address, err) } ip := net.ParseIP(host) if ip == nil { return fmt.Errorf("dial address %q did not resolve to an IP", address) } if !ssrf.IsPublicIPAddress(ip) { return fmt.Errorf("refusing to dial %s: reserved or private address", ip) } return nil } return d}
// ValidateExternalURL checks raw is a well-formed http(s) url and rejects// ip-literal hosts in blocked ranges; dns hosts are re-checked at dial time.func ValidateExternalURL(raw string, dev bool) error { u, err := url.Parse(raw) if err != nil { return fmt.Errorf("invalid URL: %w", err) } if u.Scheme != "http" && u.Scheme != "https" { return fmt.Errorf("URL must use http or https") } if u.Hostname() == "" { return fmt.Errorf("URL must include a host") } if dev { return nil } if ip := net.ParseIP(u.Hostname()); ip != nil && !ssrf.IsPublicIPAddress(ip) { return fmt.Errorf("URL host is a reserved or private address") } return nil}
// SafeClient returns an http.Client for fetching untrusted urls (e.g.// webhooks): it blocks internal address ranges and won't follow redirects.func SafeClient(dev bool, timeout time.Duration) *http.Client { return &http.Client{ Timeout: timeout, Transport: &http.Transport{ DialContext: safeDialer(dev).DialContext, }, CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }, }}