2020-01-12 18:23:35 +01:00
|
|
|
package resolver
|
|
|
|
|
|
|
|
import (
|
2020-02-17 22:06:10 +01:00
|
|
|
"crypto/tls"
|
2020-05-04 22:20:13 +02:00
|
|
|
"fmt"
|
2020-02-17 22:06:10 +01:00
|
|
|
"net/http"
|
2020-01-12 18:23:35 +01:00
|
|
|
"time"
|
|
|
|
|
2021-08-25 22:06:34 +02:00
|
|
|
"github.com/0xERR0R/blocky/config"
|
|
|
|
. "github.com/0xERR0R/blocky/helpertest"
|
|
|
|
"github.com/0xERR0R/blocky/util"
|
2020-01-12 18:23:35 +01:00
|
|
|
"github.com/miekg/dns"
|
2020-05-04 22:20:13 +02:00
|
|
|
. "github.com/onsi/ginkgo"
|
|
|
|
. "github.com/onsi/gomega"
|
2020-01-12 18:23:35 +01:00
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
2020-05-04 22:20:13 +02:00
|
|
|
var _ = Describe("UpstreamResolver", func() {
|
|
|
|
|
|
|
|
Describe("Using DNS upstream", func() {
|
|
|
|
When("Configured DNS resolver can resolve query", func() {
|
|
|
|
It("should return answer from DNS upstream", func() {
|
|
|
|
upstream := TestUDPUpstream(func(request *dns.Msg) *dns.Msg {
|
|
|
|
response, err := util.NewMsgWithAnswer("example.com", 123, dns.TypeA, "123.124.122.122")
|
|
|
|
|
|
|
|
Expect(err).Should(Succeed())
|
|
|
|
return response
|
|
|
|
})
|
|
|
|
sut := NewUpstreamResolver(upstream)
|
|
|
|
|
|
|
|
resp, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(Succeed())
|
|
|
|
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
|
|
|
|
Expect(resp.RType).Should(Equal(RESOLVED))
|
|
|
|
Expect(resp.Res.Answer).Should(BeDNSRecord("example.com.", dns.TypeA, 123, "123.124.122.122"))
|
|
|
|
Expect(resp.Reason).Should(Equal(fmt.Sprintf("RESOLVED (%s:%d)", upstream.Host, upstream.Port)))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
When("Configured DNS resolver can't resolve query", func() {
|
|
|
|
It("should return response code from DNS upstream", func() {
|
|
|
|
upstream := TestUDPUpstream(func(request *dns.Msg) *dns.Msg {
|
|
|
|
response := new(dns.Msg)
|
|
|
|
response.SetRcode(request, dns.RcodeNameError)
|
|
|
|
|
|
|
|
return response
|
|
|
|
})
|
|
|
|
sut := NewUpstreamResolver(upstream)
|
|
|
|
|
|
|
|
resp, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(Succeed())
|
|
|
|
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeNameError))
|
|
|
|
Expect(resp.RType).Should(Equal(RESOLVED))
|
|
|
|
Expect(resp.Reason).Should(Equal(fmt.Sprintf("RESOLVED (%s:%d)", upstream.Host, upstream.Port)))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
When("Configured DNS resolver fails", func() {
|
|
|
|
It("should return error", func() {
|
|
|
|
upstream := TestUDPUpstream(func(request *dns.Msg) *dns.Msg {
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
sut := NewUpstreamResolver(upstream)
|
|
|
|
|
|
|
|
_, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(HaveOccurred())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
When("Timeout occurs", func() {
|
|
|
|
counter := 0
|
|
|
|
attemptsWithTimeout := 2
|
|
|
|
upstream := TestUDPUpstream(func(request *dns.Msg) (response *dns.Msg) {
|
|
|
|
counter++
|
|
|
|
// timeout on first x attempts
|
|
|
|
if counter <= attemptsWithTimeout {
|
|
|
|
time.Sleep(110 * time.Millisecond)
|
|
|
|
}
|
|
|
|
response, err := util.NewMsgWithAnswer("example.com", 123, dns.TypeA, "123.124.122.122")
|
|
|
|
Expect(err).Should(Succeed())
|
|
|
|
|
|
|
|
return response
|
|
|
|
})
|
2020-06-21 22:37:50 +02:00
|
|
|
sut := NewUpstreamResolver(upstream)
|
|
|
|
sut.upstreamClient.(*dnsUpstreamClient).udpClient.Timeout = 100 * time.Millisecond
|
2020-05-04 22:20:13 +02:00
|
|
|
|
|
|
|
It("should perform a retry with 3 attempts", func() {
|
|
|
|
By("2 attempts with timeout -> should resolve with third attempt", func() {
|
|
|
|
counter = 0
|
|
|
|
attemptsWithTimeout = 2
|
|
|
|
|
|
|
|
resp, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(Succeed())
|
|
|
|
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
|
|
|
|
Expect(resp.Res.Answer).Should(BeDNSRecord("example.com.", dns.TypeA, 123, "123.124.122.122"))
|
|
|
|
Expect(resp.RType).Should(Equal(RESOLVED))
|
|
|
|
})
|
|
|
|
|
|
|
|
By("3 attempts with timeout -> should return error", func() {
|
|
|
|
attemptsWithTimeout = 3
|
|
|
|
counter = 0
|
|
|
|
_, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(HaveOccurred())
|
|
|
|
Expect(err.Error()).Should(ContainSubstring("i/o timeout"))
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
2020-01-12 18:23:35 +01:00
|
|
|
})
|
|
|
|
|
2020-05-04 22:20:13 +02:00
|
|
|
Describe("Using Dns over HTTP (DOH) upstream", func() {
|
|
|
|
var (
|
|
|
|
sut *UpstreamResolver
|
|
|
|
upstream config.Upstream
|
|
|
|
respFn func(request *dns.Msg) (response *dns.Msg)
|
|
|
|
modifyHTTPRespFn func(w http.ResponseWriter)
|
|
|
|
)
|
|
|
|
|
|
|
|
BeforeEach(func() {
|
|
|
|
respFn = func(_ *dns.Msg) *dns.Msg {
|
|
|
|
response, err := util.NewMsgWithAnswer("example.com", 123, dns.TypeA, "123.124.122.122")
|
|
|
|
|
|
|
|
Expect(err).Should(Succeed())
|
|
|
|
return response
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
JustBeforeEach(func() {
|
|
|
|
upstream = TestDOHUpstream(respFn, modifyHTTPRespFn)
|
2020-06-21 22:37:50 +02:00
|
|
|
sut = NewUpstreamResolver(upstream)
|
2020-05-04 22:20:13 +02:00
|
|
|
|
|
|
|
// use insecure certificates for test doh upstream
|
|
|
|
// nolint:gosec
|
|
|
|
sut.upstreamClient.(*httpUpstreamClient).client.Transport = &http.Transport{
|
|
|
|
TLSClientConfig: &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
When("Configured DOH resolver can resolve query", func() {
|
|
|
|
It("should return answer from DNS upstream", func() {
|
|
|
|
resp, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(Succeed())
|
|
|
|
Expect(resp.Res.Rcode).Should(Equal(dns.RcodeSuccess))
|
|
|
|
Expect(resp.RType).Should(Equal(RESOLVED))
|
|
|
|
Expect(resp.Res.Answer).Should(BeDNSRecord("example.com.", dns.TypeA, 123, "123.124.122.122"))
|
|
|
|
Expect(resp.Reason).Should(Equal(fmt.Sprintf("RESOLVED (https://%s:%d)", upstream.Host, upstream.Port)))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
When("Configured DOH resolver returns wrong http status code", func() {
|
|
|
|
BeforeEach(func() {
|
|
|
|
modifyHTTPRespFn = func(w http.ResponseWriter) {
|
|
|
|
w.WriteHeader(500)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
It("should return error", func() {
|
|
|
|
_, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(HaveOccurred())
|
|
|
|
Expect(err.Error()).Should(Equal("http return code should be 200, but received 500"))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
When("Configured DOH resolver returns wrong content type", func() {
|
|
|
|
BeforeEach(func() {
|
|
|
|
modifyHTTPRespFn = func(w http.ResponseWriter) {
|
|
|
|
w.Header().Set("content-type", "text")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
It("should return error", func() {
|
|
|
|
_, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(HaveOccurred())
|
|
|
|
Expect(err.Error()).Should(Equal("http return content type should be 'application/dns-message', but was 'text'"))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
When("Configured DOH resolver returns wrong content", func() {
|
|
|
|
BeforeEach(func() {
|
|
|
|
modifyHTTPRespFn = func(w http.ResponseWriter) {
|
|
|
|
_, _ = w.Write([]byte("wrongcontent"))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
It("should return error", func() {
|
|
|
|
_, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(HaveOccurred())
|
|
|
|
Expect(err.Error()).Should(Equal("can't unpack message"))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
When("Configured DOH resolver does not respond", func() {
|
|
|
|
JustBeforeEach(func() {
|
2020-06-21 22:37:50 +02:00
|
|
|
sut = NewUpstreamResolver(config.Upstream{Net: "https", Host: "wronghost.example.com"})
|
2020-05-04 22:20:13 +02:00
|
|
|
})
|
|
|
|
It("should return error", func() {
|
|
|
|
_, err := sut.Resolve(newRequest("example.com.", dns.TypeA))
|
|
|
|
Expect(err).Should(HaveOccurred())
|
2020-05-23 22:54:51 +02:00
|
|
|
Expect(err.Error()).Should(ContainSubstring("no such host"))
|
2020-05-04 22:20:13 +02:00
|
|
|
})
|
|
|
|
})
|
|
|
|
When("Configured DOH resolver receives wrong request", func() {
|
|
|
|
JustBeforeEach(func() {
|
2020-06-21 22:37:50 +02:00
|
|
|
sut = NewUpstreamResolver(config.Upstream{Net: "https", Host: "host"})
|
2020-05-04 22:20:13 +02:00
|
|
|
})
|
|
|
|
It("should return error", func() {
|
|
|
|
wrongReq := new(dns.Msg)
|
|
|
|
wrongReq.Rcode = -5
|
|
|
|
|
|
|
|
request := &Request{
|
|
|
|
Req: wrongReq,
|
|
|
|
Log: logrus.NewEntry(logrus.New()),
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := sut.Resolve(request)
|
|
|
|
Expect(err).Should(HaveOccurred())
|
|
|
|
})
|
|
|
|
})
|
2020-01-12 18:23:35 +01:00
|
|
|
})
|
2020-05-04 22:20:13 +02:00
|
|
|
Describe("Configuration", func() {
|
|
|
|
When("Configuration is called", func() {
|
|
|
|
It("should return nil, because upstream resolver is printed out by other resolvers", func() {
|
|
|
|
sut := NewUpstreamResolver(config.Upstream{})
|
2020-01-12 18:23:35 +01:00
|
|
|
|
2020-05-04 22:20:13 +02:00
|
|
|
c := sut.Configuration()
|
2020-01-12 18:23:35 +01:00
|
|
|
|
2020-05-04 22:20:13 +02:00
|
|
|
Expect(c).Should(BeNil())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|