From f7e7ca7fa35094172cd92629bfb48b17e97dae45 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Sat, 19 Sep 2026 18:57:18 +0200 Subject: [PATCH] test(06-04): add failing test for private/reserved IP table - Table-driven cases port PHP PRIVATE_V4_CIDRS/PRIVATE_V6_PREFIXES - Document Unmap() as the caller responsibility for v4-mapped literals --- fetchguard/ip_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 fetchguard/ip_test.go diff --git a/fetchguard/ip_test.go b/fetchguard/ip_test.go new file mode 100644 index 0000000..4c5d270 --- /dev/null +++ b/fetchguard/ip_test.go @@ -0,0 +1,54 @@ +package fetchguard + +import ( + "net/netip" + "testing" +) + +func TestIsReservedOrPrivate(t *testing.T) { + tests := []struct { + name string + ip string + want bool + // unmap documents that IPv4-mapped IPv6 literals are the CALLER's + // responsibility to Unmap() before classification (fetch.go dial hook). + unmap 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 after Unmap", ip: "::ffff:169.254.169.254", want: true, unmap: 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) + } + if tt.unmap { + addr = addr.Unmap() + } + got := isReservedOrPrivate(addr) + if got != tt.want { + t.Fatalf("isReservedOrPrivate(%s) = %v, want %v", addr, got, tt.want) + } + }) + } +}