@@ -15,6 +15,7 @@ import (
1515 "fmt"
1616 "io"
1717 "net"
18+ "net/netip"
1819 "net/url"
1920 "os"
2021 "os/exec"
@@ -61,6 +62,19 @@ var youtubeHosts = map[string]bool{
6162 "youtu.be" : true ,
6263}
6364
65+ var blockedIPPrefixes = []netip.Prefix {
66+ netip .MustParsePrefix ("100.64.0.0/10" ), // carrier-grade NAT / shared address space
67+ netip .MustParsePrefix ("192.0.0.0/24" ), // IETF protocol assignments
68+ netip .MustParsePrefix ("192.0.2.0/24" ), // TEST-NET-1
69+ netip .MustParsePrefix ("198.18.0.0/15" ), // benchmarking
70+ netip .MustParsePrefix ("198.51.100.0/24" ), // TEST-NET-2
71+ netip .MustParsePrefix ("203.0.113.0/24" ), // TEST-NET-3
72+ netip .MustParsePrefix ("2001:db8::/32" ), // documentation
73+ netip .MustParsePrefix ("2002::/16" ), // 6to4
74+ netip .MustParsePrefix ("64:ff9b::/96" ), // IPv4/IPv6 translation
75+ netip .MustParsePrefix ("64:ff9b:1::/48" ), // locally scoped IPv4/IPv6 translation
76+ }
77+
6478// Classify decides how a raw URL is handled, and rejects anything that is not
6579// http(s). It does not touch the network.
6680func Classify (raw string ) (Kind , error ) {
@@ -87,16 +101,28 @@ func Classify(raw string) (Kind, error) {
87101
88102// isBlockedIP reports whether an address must not be dialed: loopback,
89103// link-local (incl. the 169.254.169.254 cloud-metadata endpoint), private
90- // (RFC1918 / fc00::/7), multicast, or unspecified.
104+ // (RFC1918 / fc00::/7), shared/reserved, multicast, or unspecified.
91105func isBlockedIP (ip net.IP ) bool {
92- return ip == nil ||
106+ if ip == nil ||
93107 ip .IsLoopback () ||
94108 ip .IsLinkLocalUnicast () ||
95109 ip .IsLinkLocalMulticast () ||
96110 ip .IsInterfaceLocalMulticast () ||
97111 ip .IsMulticast () ||
98112 ip .IsUnspecified () ||
99- ip .IsPrivate ()
113+ ip .IsPrivate () {
114+ return true
115+ }
116+ addr , ok := netip .AddrFromSlice (ip )
117+ if ! ok {
118+ return true
119+ }
120+ for _ , p := range blockedIPPrefixes {
121+ if p .Contains (addr .Unmap ()) {
122+ return true
123+ }
124+ }
125+ return false
100126}
101127
102128// guardURL validates scheme and resolves the host, rejecting any URL that
0 commit comments