package fetchguard import ( "net/netip" "testing" ) func TestIsReservedOrPrivate(t *testing.T) { tests := []struct { name string ip string want bool }{ {name: "loopback v4", ip: "127.0.0.1", want: true}, {name: "rfc1918 10/8", ip: "10.1.2.3", want: true}, {name: "rfc1918 172.16/12 start", ip: "172.16.0.1", want: true}, {name: "rfc1918 172.16/12 end", ip: "172.31.255.255", want: true}, {name: "rfc1918 192.168/16", ip: "192.168.1.1", want: true}, {name: "cloud metadata link-local", ip: "169.254.169.254", want: true}, {name: "cgnat 100.64/10", ip: "100.64.0.1", want: true}, {name: "this-network 0.0.0.0/8", ip: "0.0.0.1", want: true}, {name: "public 8.8.8.8", ip: "8.8.8.8", want: false}, {name: "public 1.1.1.1", ip: "1.1.1.1", want: false}, {name: "public 93.184.216.34", ip: "93.184.216.34", want: false}, {name: "loopback v6", ip: "::1", want: true}, {name: "link-local v6", ip: "fe80::1", want: true}, {name: "unique-local v6", ip: "fc00::1", want: true}, {name: "public v6", ip: "2606:4700:4700::1111", want: false}, {name: "v4-mapped metadata", ip: "::ffff:169.254.169.254", want: true}, {name: "multicast v4", ip: "224.0.0.1", want: true}, {name: "unspecified v4", ip: "0.0.0.0", want: true}, {name: "just below 172.16.0.0/12", ip: "172.15.255.255", want: false}, {name: "just above 172.16.0.0/12", ip: "172.32.0.0", want: false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { addr, err := netip.ParseAddr(tt.ip) if err != nil { t.Fatalf("ParseAddr(%q): %v", tt.ip, err) } got := isReservedOrPrivate(addr) if got != tt.want { t.Fatalf("isReservedOrPrivate(%s) = %v, want %v", addr, got, tt.want) } }) } } func TestIsReservedOrPrivateIPv6Transitions(t *testing.T) { tests := []struct { name string ip string want bool }{ {name: "nat64 well-known loopback", ip: "64:ff9b::7f00:1", want: true}, {name: "nat64 well-known rfc1918", ip: "64:ff9b::a00:1", want: true}, {name: "nat64 well-known metadata", ip: "64:ff9b::a9fe:a9fe", want: true}, {name: "nat64 well-known public", ip: "64:ff9b::808:808", want: false}, {name: "nat64 local-use loopback", ip: "64:ff9b:1:7f00:0:100::", want: true}, {name: "nat64 local-use rfc1918", ip: "64:ff9b:1:a00:0:100::", want: true}, {name: "nat64 local-use metadata", ip: "64:ff9b:1:a9fe:a9:fe00::", want: true}, {name: "nat64 local-use public", ip: "64:ff9b:1:808:8:800::", want: false}, {name: "nat64 local-use non-zero u octet", ip: "64:ff9b:1:7f00:100:100::", want: true}, {name: "6to4 loopback", ip: "2002:7f00:1::", want: true}, {name: "6to4 rfc1918", ip: "2002:a00:1::", want: true}, {name: "6to4 metadata", ip: "2002:a9fe:a9fe::", want: true}, {name: "6to4 public", ip: "2002:808:808::", want: false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { addr := netip.MustParseAddr(tt.ip) if got := isReservedOrPrivate(addr); got != tt.want { t.Fatalf("isReservedOrPrivate(%s) = %v, want %v", addr, got, tt.want) } }) } } func TestIsReservedOrPrivateSpecialUseSmoke(t *testing.T) { for _, s := range []string{"198.18.0.1", "192.0.0.1", "240.0.0.1", "255.255.255.255", "2001:db8::1", "fec0::1", "fe80::1%eth0"} { if !isReservedOrPrivate(netip.MustParseAddr(s)) { t.Errorf("%s should be non-public", s) } } for _, s := range []string{"8.8.8.8", "1.1.1.1", "2606:4700:4700::1111"} { if isReservedOrPrivate(netip.MustParseAddr(s)) { t.Errorf("%s should be public", s) } } }