Files
dnshelper/resolver/splithorizon_test.go

165 lines
4.0 KiB
Go

package resolver_test
import (
"context"
"ekdns/resolver"
"io"
"testing"
"time"
)
// ---------------------------------------------------------------------------
// CheckSplitHorizon tests (T015)
// ---------------------------------------------------------------------------
func TestCheckSplitHorizon_NoConflict_SameIPs(t *testing.T) {
qname := mustNewName("www.example.com.")
localAddr := startFakeDNSMulti(t, func(query []byte) []byte {
return buildAResponse(queryID(query), qname, [][4]byte{{93, 184, 216, 34}})
})
authIPs := []string{"93.184.216.34"}
result := resolver.CheckSplitHorizon(
context.Background(),
io.Discard,
[]string{localAddr},
"www.example.com",
authIPs,
"ns1.example.com",
2*time.Second,
)
if result.HasConflict {
t.Errorf("expected no conflict when IPs match, got conflict: local=%v auth=%v",
result.LocalIPs, result.AuthoritativeIPs)
}
}
func TestCheckSplitHorizon_Conflict_DifferentIPs(t *testing.T) {
qname := mustNewName("www.example.com.")
// Local resolver returns internal IP.
localAddr := startFakeDNSMulti(t, func(query []byte) []byte {
return buildAResponse(queryID(query), qname, [][4]byte{{10, 0, 5, 100}})
})
authIPs := []string{"203.0.113.50"} // authoritative returned a different IP
result := resolver.CheckSplitHorizon(
context.Background(),
io.Discard,
[]string{localAddr},
"www.example.com",
authIPs,
"ns1.example.com",
2*time.Second,
)
if !result.HasConflict {
t.Error("expected conflict when IPs differ")
}
if len(result.LocalIPs) == 0 {
t.Error("expected LocalIPs to be populated")
}
if result.LocalSource == "" {
t.Error("expected LocalSource to be populated")
}
}
func TestCheckSplitHorizon_NoConflict_LocalNXDOMAIN(t *testing.T) {
qname := mustNewName("www.example.com.")
localAddr := startFakeDNSMulti(t, func(query []byte) []byte {
return buildNXDOMAINResponse(queryID(query), qname)
})
authIPs := []string{"93.184.216.34"}
result := resolver.CheckSplitHorizon(
context.Background(),
io.Discard,
[]string{localAddr},
"www.example.com",
authIPs,
"ns1.example.com",
2*time.Second,
)
if result.HasConflict {
t.Error("expected no conflict when local returns NXDOMAIN")
}
if result.LocalIPs != nil {
t.Errorf("expected nil LocalIPs for NXDOMAIN, got %v", result.LocalIPs)
}
}
func TestCheckSplitHorizon_NoConflict_LocalTimeout(t *testing.T) {
silentAddr := startSilentDNS(t)
authIPs := []string{"93.184.216.34"}
result := resolver.CheckSplitHorizon(
context.Background(),
io.Discard,
[]string{silentAddr},
"www.example.com",
authIPs,
"ns1.example.com",
100*time.Millisecond,
)
if result.HasConflict {
t.Error("expected no conflict when local resolver times out")
}
if result.LocalIPs != nil {
t.Errorf("expected nil LocalIPs for timeout, got %v", result.LocalIPs)
}
}
func TestCheckSplitHorizon_NoConflict_OrderIndependent(t *testing.T) {
qname := mustNewName("www.example.com.")
// Local resolver returns IPs in different order than authoritative.
localAddr := startFakeDNSMulti(t, func(query []byte) []byte {
return buildAResponse(queryID(query), qname, [][4]byte{
{5, 6, 7, 8},
{1, 2, 3, 4},
})
})
// Authoritative had them in reverse order.
authIPs := []string{"1.2.3.4", "5.6.7.8"}
result := resolver.CheckSplitHorizon(
context.Background(),
io.Discard,
[]string{localAddr},
"www.example.com",
authIPs,
"ns1.example.com",
2*time.Second,
)
if result.HasConflict {
t.Errorf("expected no conflict for same IPs in different order: local=%v auth=%v",
result.LocalIPs, result.AuthoritativeIPs)
}
}
func TestCheckSplitHorizon_NoLocalResolvers(t *testing.T) {
authIPs := []string{"93.184.216.34"}
result := resolver.CheckSplitHorizon(
context.Background(),
io.Discard,
nil, // no local resolvers
"www.example.com",
authIPs,
"ns1.example.com",
2*time.Second,
)
if result.HasConflict {
t.Error("expected no conflict when no local resolvers provided")
}
if result.LocalIPs != nil {
t.Error("expected nil LocalIPs when no resolvers provided")
}
}