Files
ExploreDNS/internal/traverse/response_test.go
T

341 lines
9.2 KiB
Go

package traverse
import (
"net"
"testing"
"github.com/miekg/dns"
)
func TestResponseProcessNil(t *testing.T) {
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(nil)
if r.Type != RespError {
t.Errorf("Type = %d, want %d", r.Type, RespError)
}
}
func TestResponseClassifyAnswer(t *testing.T) {
msg := new(dns.Msg)
msg.SetReply(new(dns.Msg))
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 300},
A: net.ParseIP("93.184.216.34"),
})
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
if r.Type != RespAnswer {
t.Errorf("Type = %d, want %d", r.Type, RespAnswer)
}
if r.Decoded == nil {
t.Fatal("Decoded should not be nil")
}
}
func TestResponseClassifyReferral(t *testing.T) {
msg := new(dns.Msg)
msg.Rcode = dns.RcodeSuccess
msg.Authoritative = false
msg.Ns = append(msg.Ns, &dns.NS{
Hdr: dns.RR_Header{Name: "com.", Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 172800},
Ns: "a.gtld-servers.net.",
})
msg.Extra = append(msg.Extra, &dns.A{
Hdr: dns.RR_Header{Name: "a.gtld-servers.net.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 172800},
A: net.ParseIP("192.5.6.30"),
})
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
cache := NewInfoCache(nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), cache)
r.Process(msg)
if r.Type != RespReferral {
t.Errorf("Type = %d, want %d", r.Type, RespReferral)
}
}
func TestResponseClassifyNXDOMAIN(t *testing.T) {
msg := new(dns.Msg)
msg.Rcode = dns.RcodeNameError
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
if r.Type != RespNXDOMAIN {
t.Errorf("Type = %d, want %d", r.Type, RespNXDOMAIN)
}
}
func TestResponseClassifyNODATA(t *testing.T) {
msg := new(dns.Msg)
msg.Rcode = dns.RcodeSuccess
msg.Authoritative = true
msg.Ns = append(msg.Ns, &dns.SOA{
Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 3600},
})
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
if r.Type != RespNODATA {
t.Errorf("Type = %d, want %d", r.Type, RespNODATA)
}
}
func TestResponseClassifySERVFAIL(t *testing.T) {
msg := new(dns.Msg)
msg.Rcode = dns.RcodeServerFailure
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
if r.Type != RespSERVFAIL {
t.Errorf("Type = %d, want %d", r.Type, RespSERVFAIL)
}
}
func TestResponseCNAMEFollow(t *testing.T) {
msg := new(dns.Msg)
msg.SetReply(new(dns.Msg))
msg.Answer = append(msg.Answer,
&dns.CNAME{
Hdr: dns.RR_Header{Name: "www.example.com.", Rrtype: dns.TypeCNAME, Class: dns.ClassINET},
Target: "example.com.",
},
)
ref := NewReferral("www.example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
if r.Type != RespCNAMEFollow {
t.Errorf("Type = %d, want %d", r.Type, RespCNAMEFollow)
}
}
func TestResponseCNAMEWithFinalAnswer(t *testing.T) {
msg := new(dns.Msg)
msg.SetReply(new(dns.Msg))
msg.Answer = append(msg.Answer,
&dns.CNAME{
Hdr: dns.RR_Header{Name: "www.example.com.", Rrtype: dns.TypeCNAME, Class: dns.ClassINET},
Target: "example.com.",
},
&dns.A{
Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 300},
A: net.ParseIP("93.184.216.34"),
},
)
ref := NewReferral("www.example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
if r.Type != RespAnswer {
t.Errorf("Type = %d, want %d (CNAME with final A answer)", r.Type, RespAnswer)
}
}
func TestResponseChildReferrals(t *testing.T) {
msg := new(dns.Msg)
msg.Rcode = dns.RcodeSuccess
msg.Authoritative = false
msg.Ns = append(msg.Ns,
&dns.NS{Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeNS}, Ns: "a.gtld-servers.net."},
&dns.NS{Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeNS}, Ns: "b.gtld-servers.net."},
)
msg.Extra = append(msg.Extra,
&dns.A{Hdr: dns.RR_Header{Name: "a.gtld-servers.net.", Rrtype: dns.TypeA}, A: net.ParseIP("192.5.6.30")},
&dns.A{Hdr: dns.RR_Header{Name: "b.gtld-servers.net.", Rrtype: dns.TypeA}, A: net.ParseIP("192.33.14.30")},
)
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
cache := NewInfoCache(nil)
r := NewResponse(ref, net.ParseIP("198.41.0.4"), cache)
r.Process(msg)
children := r.ChildReferrals()
if len(children) != 2 {
t.Fatalf("expected 2 child referrals, got %d", len(children))
}
if children[0].Name != "example.com." {
t.Errorf("child[0] name = %q, want example.com.", children[0].Name)
}
if children[0].Bailiwick != "a.gtld-servers.net." {
t.Errorf("child[0] bailiwick = %q, want a.gtld-servers.net.", children[0].Bailiwick)
}
if children[0].Prob != 0.5 {
t.Errorf("child[0] prob = %f, want 0.5", children[0].Prob)
}
if children[0].Depth != 1 {
t.Errorf("child[0] depth = %d, want 1", children[0].Depth)
}
if !children[0].HasAddresses() {
t.Error("child[0] should have glue addresses")
}
if !children[1].HasAddresses() {
t.Error("child[1] should have glue addresses")
}
nsNames := cache.LookupNS("example.com.")
if len(nsNames) != 2 {
t.Errorf("expected 2 NS in cache, got %d", len(nsNames))
}
}
func TestResponseChildReferralsNonReferral(t *testing.T) {
msg := new(dns.Msg)
msg.SetReply(new(dns.Msg))
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{Rrtype: dns.TypeA},
A: net.ParseIP("1.2.3.4"),
})
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
if children := r.ChildReferrals(); children != nil {
t.Error("non-referral should not produce child referrals")
}
}
func TestResponseCNAMEFollowReferral(t *testing.T) {
msg := new(dns.Msg)
msg.SetReply(new(dns.Msg))
msg.Answer = append(msg.Answer,
&dns.CNAME{
Hdr: dns.RR_Header{Name: "www.example.com.", Rrtype: dns.TypeCNAME},
Target: "example.com.",
},
)
ref := NewReferral("www.example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
follow := r.CNAMEFollowReferral()
if follow == nil {
t.Fatal("expected CNAME follow referral")
}
if follow.Name != "example.com." {
t.Errorf("follow name = %q, want %q", follow.Name, "example.com.")
}
if follow.Depth != 1 {
t.Errorf("follow depth = %d, want 1", follow.Depth)
}
}
func TestResponseIsTerminal(t *testing.T) {
tests := []struct {
respType ResponseType
want bool
}{
{RespAnswer, true},
{RespNODATA, true},
{RespNXDOMAIN, true},
{RespSERVFAIL, true},
{RespError, true},
{RespNSResolutionFailed, true},
{RespReferral, false},
{RespCNAMEFollow, false},
}
for _, tt := range tests {
t.Run(tt.respType.String(), func(t *testing.T) {
r := &Response{Type: tt.respType}
if got := r.IsTerminal(); got != tt.want {
t.Errorf("IsTerminal() = %v, want %v", got, tt.want)
}
})
}
}
func TestResponseTypeString(t *testing.T) {
tests := []struct {
rt ResponseType
want string
}{
{RespReferral, "referral"},
{RespAnswer, "answer"},
{RespCNAMEFollow, "cname_follow"},
{RespNODATA, "nodata"},
{RespNXDOMAIN, "nxdomain"},
{RespSERVFAIL, "servfail"},
{RespError, "error"},
{RespNSResolutionFailed, "ns_error"},
}
for _, tt := range tests {
t.Run(tt.want, func(t *testing.T) {
if got := tt.rt.String(); got != tt.want {
t.Errorf("String() = %q, want %q", got, tt.want)
}
})
}
}
func TestResponseChildReferralsProbabilityInheritance(t *testing.T) {
msg := new(dns.Msg)
msg.Rcode = dns.RcodeSuccess
msg.Authoritative = false
msg.Ns = append(msg.Ns,
&dns.NS{Hdr: dns.RR_Header{Name: "com.", Rrtype: dns.TypeNS}, Ns: "a.gtld-servers.net."},
&dns.NS{Hdr: dns.RR_Header{Name: "com.", Rrtype: dns.TypeNS}, Ns: "b.gtld-servers.net."},
&dns.NS{Hdr: dns.RR_Header{Name: "com.", Rrtype: dns.TypeNS}, Ns: "c.gtld-servers.net."},
)
ref := NewReferral("example.com", dns.TypeA, ".", 0, 0.5, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
children := r.ChildReferrals()
if len(children) != 3 {
t.Fatalf("expected 3 children, got %d", len(children))
}
for _, c := range children {
if c.Prob != 0.5/3.0 {
t.Errorf("child prob = %f, want %f", c.Prob, 0.5/3.0)
}
}
}
func TestResponseChildReferralsEmptyAuthority(t *testing.T) {
msg := new(dns.Msg)
msg.Rcode = dns.RcodeSuccess
msg.Authoritative = false
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
r := NewResponse(ref, net.ParseIP("1.2.3.4"), nil)
r.Process(msg)
children := r.ChildReferrals()
if len(children) != 0 {
t.Errorf("expected 0 children with empty authority, got %d", len(children))
}
}
func TestResponseNilReferral(t *testing.T) {
r := NewResponse(nil, net.ParseIP("1.2.3.4"), nil)
children := r.ChildReferrals()
if children != nil {
t.Error("nil referral should produce no children")
}
follow := r.CNAMEFollowReferral()
if follow != nil {
t.Error("nil referral should produce no CNAME follow")
}
}