Files

61 lines
1.8 KiB
Go
Raw Permalink Normal View History

//go:build linux || freebsd
// +build linux freebsd
package transport
import (
"net"
"testing"
)
// TestIsPrivateIP verifies that isPrivateIP correctly blocks private and
// reserved ranges, allows loopback and public addresses, and — critically —
// detects IPv4-mapped IPv6 representations of private addresses.
func TestIsPrivateIP(t *testing.T) {
cases := []struct {
name string
ip string
want bool
}{
// Loopback — must always pass (localhost is allowed).
{"ipv4 loopback", "127.0.0.1", false},
{"ipv6 loopback", "::1", false},
// Plain IPv4 private/reserved — must be blocked.
{"ipv4 rfc1918 10/8", "10.0.0.1", true},
{"ipv4 rfc1918 172.16/12", "172.16.0.1", true},
{"ipv4 rfc1918 192.168/16", "192.168.1.1", true},
{"ipv4 link-local", "169.254.0.1", true},
{"ipv4 unspecified", "0.0.0.0", true},
// IPv4-mapped IPv6 — must be normalized and blocked.
// This is the SSRF bypass the fix addresses.
{"ipv4-mapped private", "::ffff:10.0.0.1", true},
{"ipv4-mapped rfc1918 172.16", "::ffff:172.16.0.1", true},
{"ipv4-mapped rfc1918 192.168", "::ffff:192.168.1.1", true},
{"ipv4-mapped link-local", "::ffff:169.254.0.1", true},
{"ipv4-mapped loopback", "::ffff:127.0.0.1", false},
// Plain IPv6 private/link-local — must be blocked.
{"ipv6 unique-local fc00::/7", "fc00::1", true},
{"ipv6 link-local fe80::/10", "fe80::1", true},
// Public addresses — must pass.
{"ipv4 public", "8.8.8.8", false},
{"ipv4-mapped public", "::ffff:8.8.8.8", false},
{"ipv6 public", "2606:4700:4700::1111", false},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
ip := net.ParseIP(tc.ip)
if ip == nil {
t.Fatalf("net.ParseIP(%q) returned nil", tc.ip)
}
if got := isPrivateIP(ip); got != tc.want {
t.Errorf("isPrivateIP(%s) = %v, want %v", tc.ip, got, tc.want)
}
})
}
}