blocky/resolver/custom_dns_resolver_test.go

215 lines
7.7 KiB
Go

package resolver
import (
"net"
"time"
"github.com/0xERR0R/blocky/config"
. "github.com/0xERR0R/blocky/helpertest"
. "github.com/0xERR0R/blocky/model"
"github.com/miekg/dns"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/mock"
)
var _ = Describe("CustomDNSResolver", func() {
var (
sut ChainedResolver
m *MockResolver
err error
resp *Response
cfg config.CustomDNSConfig
)
TTL := uint32(time.Now().Second())
BeforeEach(func() {
cfg = config.CustomDNSConfig{
Mapping: config.CustomDNSMapping{HostIPs: map[string][]net.IP{
"custom.domain": {net.ParseIP("192.168.143.123")},
"ip6.domain": {net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334")},
"multiple.ips": {
net.ParseIP("192.168.143.123"),
net.ParseIP("192.168.143.125"),
net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334")},
}},
CustomTTL: config.Duration(time.Duration(TTL) * time.Second),
FilterUnmappedTypes: true,
}
})
JustBeforeEach(func() {
sut = NewCustomDNSResolver(cfg)
m = &MockResolver{}
m.On("Resolve", mock.Anything).Return(&Response{Res: new(dns.Msg)}, nil)
sut.Next(m)
})
Describe("Resolving custom name via CustomDNSResolver", func() {
When("Ip 4 mapping is defined for custom domain and", func() {
Context("filterUnmappedTypes is true", func() {
BeforeEach(func() { cfg.FilterUnmappedTypes = true })
It("defined ip4 query should be resolved", func() {
resp, err = sut.Resolve(newRequest("custom.domain.", dns.Type(dns.TypeA)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(BeDNSRecord("custom.domain.", dns.TypeA, TTL, "192.168.143.123"))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
It("TXT query for defined mapping should return NOERROR and empty result", func() {
resp, err = sut.Resolve(newRequest("custom.domain.", dns.Type(dns.TypeTXT)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(HaveLen(0))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
It("ip6 query should return NOERROR and empty result", func() {
resp, err = sut.Resolve(newRequest("custom.domain.", dns.Type(dns.TypeAAAA)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(HaveLen(0))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
})
Context("filterUnmappedTypes is false", func() {
BeforeEach(func() { cfg.FilterUnmappedTypes = false })
It("defined ip4 query should be resolved", func() {
resp, err = sut.Resolve(newRequest("custom.domain.", dns.Type(dns.TypeA)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(BeDNSRecord("custom.domain.", dns.TypeA, TTL, "192.168.143.123"))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
It("TXT query for defined mapping should be delegated to next resolver", func() {
resp, err = sut.Resolve(newRequest("custom.domain.", dns.Type(dns.TypeTXT)))
// delegate was executed
m.AssertExpectations(GinkgoT())
})
It("ip6 query should return NOERROR and empty result", func() {
resp, err = sut.Resolve(newRequest("custom.domain.", dns.Type(dns.TypeAAAA)))
// delegate was executed
m.AssertExpectations(GinkgoT())
})
})
})
When("Ip 6 mapping is defined for custom domain ", func() {
It("ip6 query should be resolved", func() {
resp, err = sut.Resolve(newRequest("ip6.domain.", dns.Type(dns.TypeAAAA)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(BeDNSRecord("ip6.domain.", dns.TypeAAAA, TTL, "2001:db8:85a3::8a2e:370:7334"))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
})
When("Multiple IPs are defined for custom domain ", func() {
It("all IPs for the current type should be returned", func() {
By("IPv6 query", func() {
resp, err = sut.Resolve(newRequest("multiple.ips.", dns.Type(dns.TypeAAAA)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(BeDNSRecord("multiple.ips.", dns.TypeAAAA, TTL, "2001:db8:85a3::8a2e:370:7334"))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
By("IPv4 query", func() {
resp, err = sut.Resolve(newRequest("multiple.ips.", dns.Type(dns.TypeA)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(HaveLen(2))
Expect(resp.Res.Answer).Should(ContainElements(
BeDNSRecord("multiple.ips.", dns.TypeA, TTL, "192.168.143.123"),
BeDNSRecord("multiple.ips.", dns.TypeA, TTL, "192.168.143.125")))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
})
})
When("Reverse DNS request is received", func() {
It("should resolve the defined domain name", func() {
By("ipv4", func() {
resp, err = sut.Resolve(newRequest("123.143.168.192.in-addr.arpa.", dns.Type(dns.TypePTR)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(HaveLen(2))
Expect(resp.Res.Answer).Should(ContainElements(
BeDNSRecord("123.143.168.192.in-addr.arpa.", dns.TypePTR, TTL, "custom.domain."),
BeDNSRecord("123.143.168.192.in-addr.arpa.", dns.TypePTR, TTL, "multiple.ips.")))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
By("ipv6", func() {
resp, err = sut.Resolve(newRequest("4.3.3.7.0.7.3.0.e.2.a.8.0.0.0.0.0.0.0.0.3.a.5.8.8.b.d.0.1.0.0.2.ip6.arpa.",
dns.Type(dns.TypePTR)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(HaveLen(2))
Expect(resp.Res.Answer).Should(ContainElements(
BeDNSRecord("4.3.3.7.0.7.3.0.e.2.a.8.0.0.0.0.0.0.0.0.3.a.5.8.8.b.d.0.1.0.0.2.ip6.arpa.",
dns.TypePTR, TTL, "ip6.domain."),
BeDNSRecord("4.3.3.7.0.7.3.0.e.2.a.8.0.0.0.0.0.0.0.0.3.a.5.8.8.b.d.0.1.0.0.2.ip6.arpa.",
dns.TypePTR, TTL, "multiple.ips.")))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
})
})
When("Domain mapping is defined", func() {
It("subdomain must also match", func() {
resp, err = sut.Resolve(newRequest("ABC.CUSTOM.DOMAIN.", dns.Type(dns.TypeA)))
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
Expect(resp.Res.Answer).Should(BeDNSRecord("ABC.CUSTOM.DOMAIN.", dns.TypeA, TTL, "192.168.143.123"))
// will not delegate to next resolver
m.AssertNotCalled(GinkgoT(), "Resolve", mock.Anything)
})
})
AfterEach(func() {
Expect(err).Should(Succeed())
})
})
Describe("Delegating to next resolver", func() {
When("no mapping for domain exist", func() {
It("should delegate to next resolver", func() {
resp, err = sut.Resolve(newRequest("example.com.", dns.Type(dns.TypeA)))
Expect(err).Should(Succeed())
// delegate was executed
m.AssertExpectations(GinkgoT())
})
})
})
Describe("Configuration output", func() {
When("resolver is enabled", func() {
It("should return configuration", func() {
c := sut.Configuration()
Expect(c).Should(HaveLen(3))
})
})
When("resolver is disabled", func() {
BeforeEach(func() {
cfg = config.CustomDNSConfig{}
})
It("should return 'disabled'", func() {
c := sut.Configuration()
Expect(c).Should(HaveLen(1))
Expect(c).Should(Equal([]string{"deactivated"}))
})
})
})
})