package guard import "net/netip" // IANA special-purpose registries (IPv4 and IPv6). Families that can embed // IPv4 (6to4, Teredo, well-known NAT64, local-use NAT64) are blocked outright // rather than decoded. IsGlobalUnicast remains a final gate in CheckAddr. // // Sources: // // https://www.iana.org/assignments/iana-ipv4-special-registry // https://www.iana.org/assignments/iana-ipv6-special-registry var ianaDeny = []struct { prefix netip.Prefix reason string }{ // IPv4 {p("0.0.0.0/8"), "unspecified address"}, {p("10.0.0.0/8"), "private address"}, {p("100.64.0.0/10"), "tailnet address"}, {p("127.0.0.0/8"), "loopback address"}, {p("169.254.0.0/16"), "link-local address"}, {p("172.16.0.0/12"), "private address"}, {p("192.0.0.0/24"), "special-purpose address"}, {p("192.0.2.0/24"), "special-purpose address"}, {p("192.31.196.0/24"), "special-purpose address"}, {p("192.52.193.0/24"), "special-purpose address"}, {p("192.88.99.0/24"), "special-purpose address"}, {p("192.168.0.0/16"), "private address"}, {p("192.175.48.0/24"), "special-purpose address"}, {p("198.18.0.0/15"), "special-purpose address"}, {p("198.51.100.0/24"), "special-purpose address"}, {p("203.0.113.0/24"), "special-purpose address"}, {p("224.0.0.0/4"), "multicast address"}, {p("240.0.0.0/4"), "special-purpose address"}, {p("255.255.255.255/32"), "special-purpose address"}, // IPv6 {p("::/128"), "unspecified address"}, {p("::1/128"), "loopback address"}, {p("64:ff9b::/96"), "NAT64 prefix"}, {p("64:ff9b:1::/48"), "NAT64 prefix"}, {p("100::/64"), "special-purpose address"}, {p("2001::/23"), "special-purpose address"}, // IETF protocol: Teredo, ORCHID, ORCHIDv2, … {p("2001:db8::/32"), "special-purpose address"}, {p("2002::/16"), "special-purpose address"}, // 6to4; do not decode embedded v4 {p("3fff::/20"), "special-purpose address"}, // documentation (RFC 9637) {p("fc00::/7"), "private address"}, {p("fe80::/10"), "link-local address"}, {p("fec0::/10"), "special-purpose address"}, // deprecated site-local {p("ff00::/8"), "multicast address"}, {p("fd7a:115c:a1e0::/48"), "tailnet address"}, } func p(s string) netip.Prefix { return netip.MustParsePrefix(s) } func checkIANA(addr netip.Addr) error { for _, e := range ianaDeny { if e.prefix.Contains(addr) { return blockedAddr(e.reason, addr) } } return nil }