github.com/letsencrypt/boulder@v0.20251208.0/iana/ip_test.go (about) 1 package iana 2 3 import ( 4 "net/netip" 5 "strings" 6 "testing" 7 ) 8 9 func TestIsReservedAddr(t *testing.T) { 10 t.Parallel() 11 12 cases := []struct { 13 ip string 14 want string 15 }{ 16 {"127.0.0.1", "Loopback"}, // second-lowest IP in a reserved /8, common mistaken request 17 {"128.0.0.1", ""}, // second-lowest IP just above a reserved /8 18 {"192.168.254.254", "Private-Use"}, // highest IP in a reserved /16 19 {"192.169.255.255", ""}, // highest IP in the /16 above a reserved /16 20 21 {"::", "Unspecified Address"}, // lowest possible IPv6 address, reserved, possible parsing edge case 22 {"::1", "Loopback Address"}, // reserved, common mistaken request 23 {"::2", ""}, // surprisingly unreserved 24 25 {"fe80::1", "Link-Local Unicast"}, // second-lowest IP in a reserved /10 26 {"febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "Link-Local Unicast"}, // highest IP in a reserved /10 27 {"fec0::1", ""}, // second-lowest IP just above a reserved /10 28 29 {"fe80::1%eth0", "Link-Local Unicast"}, // IPv6 link-local with zone 30 {"::1%lo", "Loopback Address"}, // IPv6 loopback with zone 31 32 {"192.0.0.170", "NAT64/DNS64 Discovery"}, // first of two reserved IPs that are comma-split in IANA's CSV; also a more-specific of a larger reserved block that comes first 33 {"192.0.0.171", "NAT64/DNS64 Discovery"}, // second of two reserved IPs that are comma-split in IANA's CSV; also a more-specific of a larger reserved block that comes first 34 {"2001:1::1", "Port Control Protocol Anycast"}, // reserved IP that comes after a line with a line break in IANA's CSV; also a more-specific of a larger reserved block that comes first 35 {"2002::", "6to4"}, // lowest IP in a reserved /16 that has a footnote in IANA's CSV 36 {"2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "6to4"}, // highest IP in a reserved /16 that has a footnote in IANA's CSV 37 38 {"0100::", "Discard-Only Address Block"}, // part of a reserved block in a non-canonical IPv6 format 39 {"0100::0000:ffff:ffff:ffff:ffff", "Discard-Only Address Block"}, // part of a reserved block in a non-canonical IPv6 format 40 {"0100::0002:0000:0000:0000:0000", ""}, // non-reserved but in a non-canonical IPv6 format 41 } 42 43 for _, tc := range cases { 44 t.Run(tc.ip, func(t *testing.T) { 45 t.Parallel() 46 err := IsReservedAddr(netip.MustParseAddr(tc.ip)) 47 if err == nil && tc.want != "" { 48 t.Errorf("Got success, wanted error for %#v", tc.ip) 49 } 50 if err != nil && !strings.Contains(err.Error(), tc.want) { 51 t.Errorf("%#v: got %q, want %q", tc.ip, err.Error(), tc.want) 52 } 53 }) 54 } 55 } 56 57 func TestIsReservedPrefix(t *testing.T) { 58 t.Parallel() 59 60 cases := []struct { 61 cidr string 62 want bool 63 }{ 64 {"172.16.0.0/12", true}, 65 {"172.16.0.0/32", true}, 66 {"172.16.0.1/32", true}, 67 {"172.31.255.0/24", true}, 68 {"172.31.255.255/24", true}, 69 {"172.31.255.255/32", true}, 70 {"172.32.0.0/24", false}, 71 {"172.32.0.1/32", false}, 72 73 {"100::/64", true}, 74 {"100::/128", true}, 75 {"100::1/128", true}, 76 {"100::1:ffff:ffff:ffff:ffff/128", true}, 77 {"100:0:0:2::/64", false}, 78 {"100:0:0:2::1/128", false}, 79 } 80 81 for _, tc := range cases { 82 t.Run(tc.cidr, func(t *testing.T) { 83 t.Parallel() 84 err := IsReservedPrefix(netip.MustParsePrefix(tc.cidr)) 85 if err != nil && !tc.want { 86 t.Error(err) 87 } 88 if err == nil && tc.want { 89 t.Errorf("Wanted error for %#v, got success", tc.cidr) 90 } 91 }) 92 } 93 }