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