github.com/vnforks/kid@v5.11.1+incompatible/services/httpservice/client.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package httpservice 5 6 import ( 7 "context" 8 "crypto/tls" 9 "errors" 10 "net" 11 "net/http" 12 "time" 13 14 "github.com/mattermost/mattermost-server/model" 15 ) 16 17 const ( 18 ConnectTimeout = 3 * time.Second 19 RequestTimeout = 30 * time.Second 20 ) 21 22 var reservedIPRanges []*net.IPNet 23 24 // IsReservedIP checks whether the target IP belongs to reserved IP address ranges to avoid SSRF attacks to the internal 25 // network of the Mattermost server 26 func IsReservedIP(ip net.IP) bool { 27 for _, ipRange := range reservedIPRanges { 28 if ipRange.Contains(ip) { 29 return true 30 } 31 } 32 return false 33 } 34 35 // IsOwnIP handles the special case that a request might be made to the public IP of the host which on Linux is routed 36 // directly via the loopback IP to any listening sockets, effectively bypassing host-based firewalls such as firewalld 37 func IsOwnIP(ip net.IP) (bool, error) { 38 interfaces, err := net.Interfaces() 39 if err != nil { 40 return false, err 41 } 42 43 for _, interf := range interfaces { 44 addresses, err := interf.Addrs() 45 if err != nil { 46 return false, err 47 } 48 49 for _, addr := range addresses { 50 var selfIP net.IP 51 switch v := addr.(type) { 52 case *net.IPNet: 53 selfIP = v.IP 54 case *net.IPAddr: 55 selfIP = v.IP 56 } 57 58 if ip.Equal(selfIP) { 59 return true, nil 60 } 61 } 62 } 63 64 return false, nil 65 } 66 67 var defaultUserAgent string 68 69 func init() { 70 for _, cidr := range []string{ 71 // See https://tools.ietf.org/html/rfc6890 72 "0.0.0.0/8", // This host on this network 73 "10.0.0.0/8", // Private-Use 74 "127.0.0.0/8", // Loopback 75 "169.254.0.0/16", // Link Local 76 "172.16.0.0/12", // Private-Use Networks 77 "192.168.0.0/16", // Private-Use Networks 78 "::/128", // Unspecified Address 79 "::1/128", // Loopback Address 80 "fc00::/7", // Unique-Local 81 "fe80::/10", // Linked-Scoped Unicast 82 } { 83 _, parsed, err := net.ParseCIDR(cidr) 84 if err != nil { 85 panic(err) 86 } 87 reservedIPRanges = append(reservedIPRanges, parsed) 88 } 89 defaultUserAgent = "mattermost-" + model.CurrentVersion 90 } 91 92 type DialContextFunction func(ctx context.Context, network, addr string) (net.Conn, error) 93 94 var AddressForbidden error = errors.New("address forbidden, you may need to set AllowedUntrustedInternalConnections to allow an integration access to your internal network") 95 96 func dialContextFilter(dial DialContextFunction, allowHost func(host string) bool, allowIP func(ip net.IP) bool) DialContextFunction { 97 return func(ctx context.Context, network, addr string) (net.Conn, error) { 98 host, port, err := net.SplitHostPort(addr) 99 if err != nil { 100 return nil, err 101 } 102 103 if allowHost != nil && allowHost(host) { 104 return dial(ctx, network, addr) 105 } 106 107 ips, err := net.LookupIP(host) 108 if err != nil { 109 return nil, err 110 } 111 112 var firstErr error 113 for _, ip := range ips { 114 select { 115 case <-ctx.Done(): 116 return nil, ctx.Err() 117 default: 118 } 119 120 if allowIP == nil || !allowIP(ip) { 121 continue 122 } 123 124 conn, err := dial(ctx, network, net.JoinHostPort(ip.String(), port)) 125 if err == nil { 126 return conn, nil 127 } 128 if firstErr == nil { 129 firstErr = err 130 } 131 } 132 if firstErr == nil { 133 return nil, AddressForbidden 134 } 135 return nil, firstErr 136 } 137 } 138 139 func NewTransport(enableInsecureConnections bool, allowHost func(host string) bool, allowIP func(ip net.IP) bool) http.RoundTripper { 140 dialContext := (&net.Dialer{ 141 Timeout: ConnectTimeout, 142 KeepAlive: 30 * time.Second, 143 }).DialContext 144 145 if allowHost != nil || allowIP != nil { 146 dialContext = dialContextFilter(dialContext, allowHost, allowIP) 147 } 148 149 return &MattermostTransport{ 150 &http.Transport{ 151 Proxy: http.ProxyFromEnvironment, 152 DialContext: dialContext, 153 MaxIdleConns: 100, 154 IdleConnTimeout: 90 * time.Second, 155 TLSHandshakeTimeout: ConnectTimeout, 156 ExpectContinueTimeout: 1 * time.Second, 157 TLSClientConfig: &tls.Config{ 158 InsecureSkipVerify: enableInsecureConnections, 159 }, 160 }, 161 } 162 }