p0: IANA special-purpose deny table, extra deny prefixes

Block 6to4/Teredo/NAT64-local/site-local/benchmarking/reserved
ranges from the IANA registries (families, not decoded embeds).
Guard.DenyPrefixes / -deny-prefix covers hairpin WAN /32s; home
addresses stay on-box, not in git. Control is tcp/tcp4/tcp6 only.
This commit is contained in:
2026-09-22 21:33:52 -07:00
parent 3b41d6ffbc
commit 099b94979c
6 changed files with 236 additions and 34 deletions
+90
View File
@@ -539,3 +539,93 @@ func TestDialerType(t *testing.T) {
t.Fatal("not a Dialer")
}
}
func TestIANASpecialPurpose(t *testing.T) {
t.Parallel()
// One address per required prefix from the P0 review.
blocked := []string{
"2002:a00:1::1", // 6to4 of 10.0.0.1
"2002:7f00:1::1", // 6to4 of 127.0.0.1
"2001::1", // Teredo 2001::/32 (inside 2001::/23)
"64:ff9b:1::a00:1", // RFC 8215 local-use NAT64 embedding 10.0.0.1
"fec0::1", // deprecated site-local
"198.18.0.1", // benchmarking
"198.19.255.255",
"192.0.0.1",
"240.0.0.1",
"255.255.255.255",
"100::1",
"2001:db8::1",
"2001:10::1", // ORCHID
"2001:20::1", // ORCHIDv2
}
for _, s := range blocked {
t.Run(s, func(t *testing.T) {
t.Parallel()
err := CheckAddr(mustAddr(s))
if err == nil {
t.Fatalf("CheckAddr(%s) = nil, want blocked", s)
}
if !strings.HasPrefix(err.Error(), "blocked:") {
t.Fatalf("%s: %v", s, err)
}
})
}
allowed := []string{"8.8.8.8", "1.1.1.1", "2001:4860:4860::8888"}
for _, s := range allowed {
if err := CheckAddr(mustAddr(s)); err != nil {
t.Fatalf("CheckAddr(%s) = %v, want allow", s, err)
}
}
}
func TestConfiguredDenyPrefix(t *testing.T) {
t.Parallel()
// 8.8.8.8 is allowed by the IANA table; a configured deny must still block
// it (the hairpin/WAN case).
g := &Guard{
DenyPrefixes: []netip.Prefix{netip.MustParsePrefix("8.8.8.8/32")},
LookupIP: func(_ context.Context, host string) ([]netip.Addr, error) {
return []netip.Addr{mustAddr("8.8.8.8")}, nil
},
}
if err := CheckAddr(mustAddr("8.8.8.8")); err != nil {
t.Fatalf("default CheckAddr allowed-set: %v", err)
}
if err := g.CheckAddr(mustAddr("8.8.8.8")); err == nil {
t.Fatal("configured /32 allowed")
}
if !strings.Contains(errString(g.CheckAddr(mustAddr("8.8.8.8"))), "denied prefix") {
t.Fatalf("want denied prefix, got %v", g.CheckAddr(mustAddr("8.8.8.8")))
}
if _, _, err := g.CheckURL(context.Background(), "http://hairpin.example/"); err == nil {
t.Fatal("CheckURL with injected denied address allowed")
}
if err := g.Control("tcp", "8.8.8.8:80", nopConn{}); err == nil {
t.Fatal("Control allowed configured deny")
}
if err := g.CheckAddr(mustAddr("1.1.1.1")); err != nil {
t.Fatalf("unrelated public: %v", err)
}
}
func errString(err error) string {
if err == nil {
return ""
}
return err.Error()
}
func TestControlRejectsNonTCP(t *testing.T) {
t.Parallel()
g := &Guard{}
if err := g.Control("udp", "8.8.8.8:80", nopConn{}); err == nil {
t.Fatal("udp allowed")
}
if err := g.Control("tcp4", "8.8.8.8:80", nopConn{}); err != nil {
t.Fatal(err)
}
if err := g.Control("tcp6", "[2001:4860:4860::8888]:443", nopConn{}); err != nil {
t.Fatal(err)
}
}