This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / hostutil / safedial.go
2.3 kB 84 lines
1package hostutil 2 3import ( 4 "fmt" 5 "net" 6 "net/http" 7 "net/url" 8 "syscall" 9 "time" 10) 11 12// isBlockedIP reports whether ip is loopback, private, link-local (incl. the 13// 169.254.169.254 metadata endpoint), multicast, or unspecified. 14func isBlockedIP(ip net.IP) bool { 15 return ip.IsLoopback() || 16 ip.IsPrivate() || 17 ip.IsLinkLocalUnicast() || 18 ip.IsLinkLocalMulticast() || 19 ip.IsMulticast() || 20 ip.IsUnspecified() 21} 22 23// safeDialer rejects dials to non-public addresses. the Control hook runs after 24// dns resolution, so it also covers rebinding and redirects. disabled in dev. 25func safeDialer(dev bool) *net.Dialer { 26 d := &net.Dialer{ 27 Timeout: 10 * time.Second, 28 KeepAlive: 30 * time.Second, 29 } 30 if dev { 31 return d 32 } 33 d.Control = func(_, address string, _ syscall.RawConn) error { 34 host, _, err := net.SplitHostPort(address) 35 if err != nil { 36 return fmt.Errorf("invalid dial address %q: %w", address, err) 37 } 38 ip := net.ParseIP(host) 39 if ip == nil { 40 return fmt.Errorf("dial address %q did not resolve to an IP", address) 41 } 42 if isBlockedIP(ip) { 43 return fmt.Errorf("refusing to dial %s: reserved or private address", ip) 44 } 45 return nil 46 } 47 return d 48} 49 50// ValidateExternalURL checks raw is a well-formed http(s) url and rejects 51// ip-literal hosts in blocked ranges; dns hosts are re-checked at dial time. 52func ValidateExternalURL(raw string, dev bool) error { 53 u, err := url.Parse(raw) 54 if err != nil { 55 return fmt.Errorf("invalid URL: %w", err) 56 } 57 if u.Scheme != "http" && u.Scheme != "https" { 58 return fmt.Errorf("URL must use http or https") 59 } 60 if u.Hostname() == "" { 61 return fmt.Errorf("URL must include a host") 62 } 63 if dev { 64 return nil 65 } 66 if ip := net.ParseIP(u.Hostname()); ip != nil && isBlockedIP(ip) { 67 return fmt.Errorf("URL host is a reserved or private address") 68 } 69 return nil 70} 71 72// SafeClient returns an http.Client for fetching untrusted urls (e.g. 73// webhooks): it blocks internal address ranges and won't follow redirects. 74func SafeClient(dev bool, timeout time.Duration) *http.Client { 75 return &http.Client{ 76 Timeout: timeout, 77 Transport: &http.Transport{ 78 DialContext: safeDialer(dev).DialContext, 79 }, 80 CheckRedirect: func(*http.Request, []*http.Request) error { 81 return http.ErrUseLastResponse 82 }, 83 } 84}