Commit 0babae2db0
Verified · cmc
Layout: unified · split
internal/webhook/webhook.go +8 −4
| @@ -48,9 +48,9 @@ func ValidateURL(raw string, allowLocal bool) error { | |||
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | // CheckAddrs refuses host when any of its resolved addresses is | 50 | // CheckAddrs refuses host when any of its resolved addresses is |
| 51 | // loopback, private or link-local, unless allowLocal. A caller resolves | 51 | // loopback, private, shared (100.64.0.0/10), link-local, multicast or |
| 52 | // immediately before connecting and connects only to the addresses it | 52 | // unspecified, unless allowLocal. A caller resolves immediately before |
| 53 | // checked. | 53 | // connecting and connects only to the addresses it checked. |
| 54 | func CheckAddrs(host string, ips []net.IP, allowLocal bool) error { | 54 | func CheckAddrs(host string, ips []net.IP, allowLocal bool) error { |
| 55 | if allowLocal { | 55 | if allowLocal { |
| 56 | return nil | 56 | return nil |
| @@ -63,9 +63,13 @@ func CheckAddrs(host string, ips []net.IP, allowLocal bool) error { | |||
| 63 | return nil | 63 | return nil |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | // cgnat is the shared address space of RFC 6598, which carriers and | ||
| 67 | // overlay networks such as Tailscale use as private space. | ||
| 68 | var cgnat = &net.IPNet{IP: net.IPv4(100, 64, 0, 0), Mask: net.CIDRMask(10, 32)} | ||
| 69 | |||
| 66 | func isForbidden(ip net.IP) bool { | 70 | func isForbidden(ip net.IP) bool { |
| 67 | return ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || | 71 | return ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || |
| 68 | ip.IsLinkLocalMulticast() || ip.IsUnspecified() | 72 | ip.IsMulticast() || ip.IsUnspecified() || cgnat.Contains(ip) |
| 69 | } | 73 | } |
| 70 | 74 | ||
| 71 | type Deliverer struct { | 75 | type Deliverer struct { |
internal/webhook/webhook_test.go +13
| @@ -19,3 +19,16 @@ func TestCheckAddrs(t *testing.T) { | |||
| 19 | t.Fatalf("allow_local: %v", err) | 19 | t.Fatalf("allow_local: %v", err) |
| 20 | } | 20 | } |
| 21 | } | 21 | } |
| 22 | |||
| 23 | func TestIsForbiddenCGNATAndMulticast(t *testing.T) { | ||
| 24 | for _, s := range []string{"100.64.0.1", "100.127.255.254", "224.0.0.251", "239.1.2.3", "ff02::1", "ff0e::1"} { | ||
| 25 | if !isForbidden(net.ParseIP(s)) { | ||
| 26 | t.Errorf("%s allowed", s) | ||
| 27 | } | ||
| 28 | } | ||
| 29 | for _, s := range []string{"100.63.255.255", "100.128.0.1", "203.0.113.5", "2001:db8::1"} { | ||
| 30 | if isForbidden(net.ParseIP(s)) { | ||
| 31 | t.Errorf("%s refused", s) | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||