61 lines
1.8 KiB
Go
61 lines
1.8 KiB
Go
//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)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|