2019-11-29 06:59:40 -05:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
2017-05-31 10:34:05 -04:00
2018-09-26 12:42:51 -04:00
package httpservice
2017-05-31 10:34:05 -04:00
import (
2017-08-09 16:49:07 -04:00
"context"
2017-05-31 10:34:05 -04:00
"crypto/tls"
2017-08-09 16:49:07 -04:00
"errors"
2017-05-31 10:34:05 -04:00
"net"
"net/http"
"time"
2018-10-03 13:28:44 -04:00
2019-11-28 08:39:38 -05:00
"github.com/mattermost/mattermost-server/v5/model"
2017-05-31 10:34:05 -04:00
)
const (
2018-12-12 11:39:14 -05:00
ConnectTimeout = 3 * time . Second
RequestTimeout = 30 * time . Second
2017-05-31 10:34:05 -04:00
)
2017-08-09 16:49:07 -04:00
var reservedIPRanges [ ] * net . IPNet
2019-03-01 10:22:24 -05:00
// IsReservedIP checks whether the target IP belongs to reserved IP address ranges to avoid SSRF attacks to the internal
// network of the Mattermost server
2017-11-22 10:15:03 -05:00
func IsReservedIP ( ip net . IP ) bool {
2017-08-09 16:49:07 -04:00
for _ , ipRange := range reservedIPRanges {
if ipRange . Contains ( ip ) {
return true
}
}
return false
}
2019-03-01 10:22:24 -05:00
// IsOwnIP handles the special case that a request might be made to the public IP of the host which on Linux is routed
// directly via the loopback IP to any listening sockets, effectively bypassing host-based firewalls such as firewalld
func IsOwnIP ( ip net . IP ) ( bool , error ) {
interfaces , err := net . Interfaces ( )
if err != nil {
return false , err
}
for _ , interf := range interfaces {
addresses , err := interf . Addrs ( )
if err != nil {
return false , err
}
for _ , addr := range addresses {
var selfIP net . IP
switch v := addr . ( type ) {
case * net . IPNet :
selfIP = v . IP
case * net . IPAddr :
selfIP = v . IP
}
if ip . Equal ( selfIP ) {
return true , nil
}
}
}
return false , nil
}
2018-10-03 13:28:44 -04:00
var defaultUserAgent string
2017-08-09 16:49:07 -04:00
func init ( ) {
for _ , cidr := range [ ] string {
// See https://tools.ietf.org/html/rfc6890
"0.0.0.0/8" , // This host on this network
"10.0.0.0/8" , // Private-Use
"127.0.0.0/8" , // Loopback
"169.254.0.0/16" , // Link Local
"172.16.0.0/12" , // Private-Use Networks
"192.168.0.0/16" , // Private-Use Networks
"::/128" , // Unspecified Address
"::1/128" , // Loopback Address
"fc00::/7" , // Unique-Local
"fe80::/10" , // Linked-Scoped Unicast
} {
_ , parsed , err := net . ParseCIDR ( cidr )
if err != nil {
panic ( err )
}
reservedIPRanges = append ( reservedIPRanges , parsed )
}
2018-10-03 13:28:44 -04:00
defaultUserAgent = "mattermost-" + model . CurrentVersion
2017-08-09 16:49:07 -04:00
}
type DialContextFunction func ( ctx context . Context , network , addr string ) ( net . Conn , error )
2018-09-02 03:30:10 -04:00
var AddressForbidden error = errors . New ( "address forbidden, you may need to set AllowedUntrustedInternalConnections to allow an integration access to your internal network" )
2017-08-09 16:49:07 -04:00
func dialContextFilter ( dial DialContextFunction , allowHost func ( host string ) bool , allowIP func ( ip net . IP ) bool ) DialContextFunction {
return func ( ctx context . Context , network , addr string ) ( net . Conn , error ) {
host , port , err := net . SplitHostPort ( addr )
if err != nil {
return nil , err
}
if allowHost != nil && allowHost ( host ) {
return dial ( ctx , network , addr )
}
ips , err := net . LookupIP ( host )
if err != nil {
return nil , err
}
var firstErr error
for _ , ip := range ips {
select {
case <- ctx . Done ( ) :
return nil , ctx . Err ( )
default :
}
if allowIP == nil || ! allowIP ( ip ) {
continue
}
conn , err := dial ( ctx , network , net . JoinHostPort ( ip . String ( ) , port ) )
if err == nil {
return conn , nil
}
if firstErr == nil {
firstErr = err
}
}
if firstErr == nil {
return nil , AddressForbidden
}
return nil , firstErr
}
}
2018-12-12 11:39:14 -05:00
func NewTransport ( enableInsecureConnections bool , allowHost func ( host string ) bool , allowIP func ( ip net . IP ) bool ) http . RoundTripper {
2017-08-09 16:49:07 -04:00
dialContext := ( & net . Dialer {
2018-12-12 11:39:14 -05:00
Timeout : ConnectTimeout ,
2017-08-09 16:49:07 -04:00
KeepAlive : 30 * time . Second ,
} ) . DialContext
if allowHost != nil || allowIP != nil {
dialContext = dialContextFilter ( dialContext , allowHost , allowIP )
}
2017-05-31 10:34:05 -04:00
2018-12-12 11:39:14 -05:00
return & MattermostTransport {
& http . Transport {
2017-08-09 16:49:07 -04:00
Proxy : http . ProxyFromEnvironment ,
DialContext : dialContext ,
2017-05-31 10:34:05 -04:00
MaxIdleConns : 100 ,
IdleConnTimeout : 90 * time . Second ,
2018-12-12 11:39:14 -05:00
TLSHandshakeTimeout : ConnectTimeout ,
2017-05-31 10:34:05 -04:00
ExpectContinueTimeout : 1 * time . Second ,
TLSClientConfig : & tls . Config {
InsecureSkipVerify : enableInsecureConnections ,
} ,
} ,
}
2018-12-12 11:39:14 -05:00
}