github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/services/httpservice/client.go (about)

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