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:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user