github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/util/net/firewall_dialer.go (about)

     1  package net
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"syscall"
     7  
     8  	"github.com/grafana/dskit/flagext"
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  var errBlockedAddress = errors.New("blocked address")
    13  var errInvalidAddress = errors.New("invalid address")
    14  
    15  type FirewallDialerConfigProvider interface {
    16  	BlockCIDRNetworks() []flagext.CIDR
    17  	BlockPrivateAddresses() bool
    18  }
    19  
    20  // FirewallDialer is a net dialer which integrates a firewall to block specific addresses.
    21  type FirewallDialer struct {
    22  	parent      *net.Dialer
    23  	cfgProvider FirewallDialerConfigProvider
    24  }
    25  
    26  func NewFirewallDialer(cfgProvider FirewallDialerConfigProvider) *FirewallDialer {
    27  	d := &FirewallDialer{cfgProvider: cfgProvider}
    28  	d.parent = &net.Dialer{Control: d.control}
    29  	return d
    30  }
    31  
    32  func (d *FirewallDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
    33  	return d.parent.DialContext(ctx, network, address)
    34  }
    35  
    36  func (d *FirewallDialer) control(_, address string, _ syscall.RawConn) error {
    37  	blockPrivateAddresses := d.cfgProvider.BlockPrivateAddresses()
    38  	blockCIDRNetworks := d.cfgProvider.BlockCIDRNetworks()
    39  
    40  	// Skip any control if no firewall has been configured.
    41  	if !blockPrivateAddresses && len(blockCIDRNetworks) == 0 {
    42  		return nil
    43  	}
    44  
    45  	host, _, err := net.SplitHostPort(address)
    46  	if err != nil {
    47  		return errInvalidAddress
    48  	}
    49  
    50  	// We expect an IP as address because the DNS resolution already occurred.
    51  	ip := net.ParseIP(host)
    52  	if ip == nil {
    53  		return errBlockedAddress
    54  	}
    55  
    56  	if blockPrivateAddresses && (isPrivate(ip) || isLocal(ip)) {
    57  		return errBlockedAddress
    58  	}
    59  
    60  	for _, cidr := range blockCIDRNetworks {
    61  		if cidr.Value.Contains(ip) {
    62  			return errBlockedAddress
    63  		}
    64  	}
    65  
    66  	return nil
    67  }
    68  
    69  func isLocal(ip net.IP) bool {
    70  	return ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast()
    71  }
    72  
    73  // isPrivate reports whether ip is a private address, according to
    74  // RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses).
    75  //
    76  // This function has been copied from golang and should be removed once
    77  // we'll upgrade to go 1.17. See: https://github.com/golang/go/pull/42793
    78  func isPrivate(ip net.IP) bool {
    79  	if ip4 := ip.To4(); ip4 != nil {
    80  		// Following RFC 4193, Section 3. Local IPv6 Unicast Addresses which says:
    81  		//   The Internet Assigned Numbers Authority (IANA) has reserved the
    82  		//   following three blocks of the IPv4 address space for private internets:
    83  		//     10.0.0.0        -   10.255.255.255  (10/8 prefix)
    84  		//     172.16.0.0      -   172.31.255.255  (172.16/12 prefix)
    85  		//     192.168.0.0     -   192.168.255.255 (192.168/16 prefix)
    86  		return ip4[0] == 10 ||
    87  			(ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
    88  			(ip4[0] == 192 && ip4[1] == 168)
    89  	}
    90  	// Following RFC 4193, Section 3. Private Address Space which says:
    91  	//   The Internet Assigned Numbers Authority (IANA) has reserved the
    92  	//   following block of the IPv6 address space for local internets:
    93  	//     FC00::  -  FDFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF (FC00::/7 prefix)
    94  	return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc
    95  }