2018-12-05 17:13:35 +00:00
|
|
|
|
package dnsforward
|
|
|
|
|
|
|
|
|
|
import (
|
2021-02-02 12:13:12 +00:00
|
|
|
|
"context"
|
2019-02-22 12:23:39 +00:00
|
|
|
|
"crypto/ecdsa"
|
|
|
|
|
"crypto/rand"
|
|
|
|
|
"crypto/rsa"
|
2021-02-02 12:13:12 +00:00
|
|
|
|
"crypto/sha256"
|
2019-02-22 12:23:39 +00:00
|
|
|
|
"crypto/tls"
|
|
|
|
|
"crypto/x509"
|
|
|
|
|
"crypto/x509/pkix"
|
|
|
|
|
"encoding/pem"
|
2020-09-08 14:20:24 +00:00
|
|
|
|
"fmt"
|
2020-09-11 08:53:36 +00:00
|
|
|
|
"io/ioutil"
|
2019-02-22 12:23:39 +00:00
|
|
|
|
"math/big"
|
2018-12-05 17:13:35 +00:00
|
|
|
|
"net"
|
2020-09-11 08:53:36 +00:00
|
|
|
|
"os"
|
2020-01-22 15:40:43 +00:00
|
|
|
|
"sort"
|
2019-02-22 12:23:39 +00:00
|
|
|
|
"sync"
|
2018-12-05 17:13:35 +00:00
|
|
|
|
"testing"
|
2018-12-24 12:19:52 +00:00
|
|
|
|
"time"
|
|
|
|
|
|
2020-11-16 12:52:05 +00:00
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/testutil"
|
2020-10-30 10:32:02 +00:00
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
2020-09-11 08:53:36 +00:00
|
|
|
|
|
2020-10-30 10:32:02 +00:00
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
|
2019-05-30 12:36:39 +00:00
|
|
|
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
2019-11-21 13:13:19 +00:00
|
|
|
|
"github.com/AdguardTeam/dnsproxy/upstream"
|
2018-12-05 17:13:35 +00:00
|
|
|
|
"github.com/miekg/dns"
|
2019-10-31 09:32:14 +00:00
|
|
|
|
"github.com/stretchr/testify/assert"
|
2018-12-05 17:13:35 +00:00
|
|
|
|
)
|
|
|
|
|
|
2020-11-16 12:52:05 +00:00
|
|
|
|
func TestMain(m *testing.M) {
|
|
|
|
|
testutil.DiscardLogOutput(m)
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-22 12:23:39 +00:00
|
|
|
|
const (
|
|
|
|
|
tlsServerName = "testdns.adguard.com"
|
|
|
|
|
testMessagesCount = 10
|
|
|
|
|
)
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
func startDeferStop(t *testing.T, s *Server) {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
err := s.Start()
|
|
|
|
|
assert.Nilf(t, err, "failed to start server: %s", err)
|
|
|
|
|
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
err := s.Stop()
|
|
|
|
|
assert.Nilf(t, err, "dns server failed to stop: %s", err)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-05 17:13:35 +00:00
|
|
|
|
func TestServer(t *testing.T) {
|
2019-02-10 17:47:43 +00:00
|
|
|
|
s := createTestServer(t)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
ipv4: map[string][]net.IP{
|
|
|
|
|
"google-public-dns-a.google.com.": {{8, 8, 8, 8}},
|
|
|
|
|
},
|
|
|
|
|
},
|
2018-12-05 17:13:35 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
|
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
|
name string
|
|
|
|
|
proto string
|
|
|
|
|
}{{
|
|
|
|
|
name: "message_over_udp",
|
|
|
|
|
proto: proxy.ProtoUDP,
|
|
|
|
|
}, {
|
|
|
|
|
name: "message_over_tcp",
|
|
|
|
|
proto: proxy.ProtoTCP,
|
|
|
|
|
}}
|
2018-12-05 17:13:35 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
for _, tc := range testCases {
|
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
|
addr := s.dnsProxy.Addr(tc.proto)
|
|
|
|
|
client := dns.Client{Net: tc.proto}
|
2018-12-05 17:13:35 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
reply, _, err := client.Exchange(createGoogleATestMessage(), addr.String())
|
|
|
|
|
assert.Nilf(t, err, "сouldn't talk to server %s: %s", addr, err)
|
2018-12-05 17:13:35 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assertGoogleAResponse(t, reply)
|
|
|
|
|
})
|
2018-12-24 12:19:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-19 21:55:32 +00:00
|
|
|
|
func TestServerWithProtectionDisabled(t *testing.T) {
|
|
|
|
|
s := createTestServer(t)
|
|
|
|
|
s.conf.ProtectionEnabled = false
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
ipv4: map[string][]net.IP{
|
|
|
|
|
"google-public-dns-a.google.com.": {{8, 8, 8, 8}},
|
|
|
|
|
},
|
|
|
|
|
},
|
2019-08-19 21:55:32 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
2019-08-19 21:55:32 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Message over UDP.
|
2019-08-19 21:55:32 +00:00
|
|
|
|
req := createGoogleATestMessage()
|
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
client := dns.Client{Net: proxy.ProtoUDP}
|
2019-08-19 21:55:32 +00:00
|
|
|
|
reply, _, err := client.Exchange(req, addr.String())
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "сouldn't talk to server %s: %s", addr, err)
|
2019-08-19 21:55:32 +00:00
|
|
|
|
assertGoogleAResponse(t, reply)
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
func createTestTLS(t *testing.T, tlsConf TLSConfig) (s *Server, certPem []byte) {
|
|
|
|
|
t.Helper()
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
var keyPem []byte
|
|
|
|
|
_, certPem, keyPem = createServerTLSConfig(t)
|
|
|
|
|
s = createTestServer(t)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem
|
|
|
|
|
s.conf.TLSConfig = tlsConf
|
|
|
|
|
|
|
|
|
|
err := s.Prepare(nil)
|
|
|
|
|
assert.Nilf(t, err, "failed to prepare server: %s", err)
|
|
|
|
|
|
|
|
|
|
return s, certPem
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDoTServer(t *testing.T) {
|
|
|
|
|
s, certPem := createTestTLS(t, TLSConfig{
|
|
|
|
|
TLSListenAddr: &net.TCPAddr{Port: 0},
|
|
|
|
|
})
|
|
|
|
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
ipv4: map[string][]net.IP{
|
|
|
|
|
"google-public-dns-a.google.com.": {{8, 8, 8, 8}},
|
|
|
|
|
},
|
|
|
|
|
},
|
2019-02-22 12:23:39 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Add our self-signed generated config to roots.
|
2019-02-22 12:23:39 +00:00
|
|
|
|
roots := x509.NewCertPool()
|
|
|
|
|
roots.AppendCertsFromPEM(certPem)
|
2019-04-17 09:02:56 +00:00
|
|
|
|
tlsConfig := &tls.Config{
|
|
|
|
|
ServerName: tlsServerName,
|
|
|
|
|
RootCAs: roots,
|
|
|
|
|
MinVersion: tls.VersionTLS12,
|
|
|
|
|
}
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Create a DNS-over-TLS client connection.
|
2019-02-22 12:23:39 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoTLS)
|
|
|
|
|
conn, err := dns.DialWithTLS("tcp-tls", addr.String(), tlsConfig)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "cannot connect to the proxy: %s", err)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
|
|
|
|
sendTestMessages(t, conn)
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
func TestDoQServer(t *testing.T) {
|
|
|
|
|
s, _ := createTestTLS(t, TLSConfig{
|
|
|
|
|
QUICListenAddr: &net.UDPAddr{Port: 0},
|
|
|
|
|
})
|
|
|
|
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
ipv4: map[string][]net.IP{
|
|
|
|
|
"google-public-dns-a.google.com.": {{8, 8, 8, 8}},
|
|
|
|
|
},
|
|
|
|
|
},
|
2020-09-08 14:20:24 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
2020-09-08 14:20:24 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Create a DNS-over-QUIC upstream.
|
2020-09-08 14:20:24 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoQUIC)
|
|
|
|
|
opts := upstream.Options{InsecureSkipVerify: true}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
u, err := upstream.AddressToUpstream(fmt.Sprintf("%s://%s", proxy.ProtoQUIC, addr), opts)
|
2020-09-08 14:20:24 +00:00
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Send the test message.
|
2020-09-08 14:20:24 +00:00
|
|
|
|
req := createGoogleATestMessage()
|
|
|
|
|
res, err := u.Exchange(req)
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assertGoogleAResponse(t, res)
|
2020-09-08 14:20:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-22 12:23:39 +00:00
|
|
|
|
func TestServerRace(t *testing.T) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
t.Skip("TODO(e.burkov): inspect the golibs/cache package for locks")
|
|
|
|
|
|
2019-02-22 12:23:39 +00:00
|
|
|
|
s := createTestServer(t)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
ipv4: map[string][]net.IP{
|
|
|
|
|
"google-public-dns-a.google.com.": {{8, 8, 8, 8}},
|
|
|
|
|
},
|
|
|
|
|
},
|
2019-02-22 12:23:39 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Message over UDP.
|
2019-02-22 12:23:39 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
conn, err := dns.Dial(proxy.ProtoUDP, addr.String())
|
|
|
|
|
assert.Nilf(t, err, "cannot connect to the proxy: %s", err)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
|
|
|
|
sendTestMessagesAsync(t, conn)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
}
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// testResolver is a Resolver for tests.
|
|
|
|
|
//
|
|
|
|
|
//lint:ignore U1000 TODO(e.burkov): move into aghtest package.
|
|
|
|
|
type testResolver struct{}
|
|
|
|
|
|
|
|
|
|
// LookupIPAddr implements Resolver interface for *testResolver.
|
|
|
|
|
//
|
|
|
|
|
//lint:ignore U1000 TODO(e.burkov): move into aghtest package.
|
|
|
|
|
func (r *testResolver) LookupIPAddr(_ context.Context, host string) (ips []net.IPAddr, err error) {
|
|
|
|
|
hash := sha256.Sum256([]byte(host))
|
|
|
|
|
addrs := []net.IPAddr{{
|
|
|
|
|
IP: net.IP(hash[:4]),
|
|
|
|
|
Zone: "somezone",
|
|
|
|
|
}, {
|
|
|
|
|
IP: net.IP(hash[4:20]),
|
|
|
|
|
Zone: "somezone",
|
|
|
|
|
}}
|
|
|
|
|
return addrs, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LookupHost implements Resolver interface for *testResolver.
|
|
|
|
|
//
|
|
|
|
|
//lint:ignore U1000 TODO(e.burkov): move into aghtest package.
|
|
|
|
|
func (r *testResolver) LookupHost(host string) (addrs []string, err error) {
|
|
|
|
|
hash := sha256.Sum256([]byte(host))
|
|
|
|
|
addrs = []string{
|
|
|
|
|
net.IP(hash[:4]).String(),
|
|
|
|
|
net.IP(hash[4:20]).String(),
|
2019-02-22 12:23:39 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
return addrs, nil
|
2019-02-22 12:23:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-25 11:58:54 +00:00
|
|
|
|
func TestSafeSearch(t *testing.T) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
t.Skip("TODO(e.burkov): substitute the dnsfilter by one with custom resolver from aghtest")
|
2019-02-25 11:58:54 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
testUpstreamIP := net.IP{213, 180, 193, 56}
|
|
|
|
|
testCases := []string{
|
|
|
|
|
"yandex.com.",
|
|
|
|
|
"yandex.by.",
|
|
|
|
|
"yandex.kz.",
|
|
|
|
|
"yandex.ru.",
|
|
|
|
|
"www.google.com.",
|
|
|
|
|
"www.google.com.af.",
|
|
|
|
|
"www.google.be.",
|
|
|
|
|
"www.google.by.",
|
2019-02-25 11:58:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
for _, tc := range testCases {
|
|
|
|
|
t.Run("safe_search_"+tc, func(t *testing.T) {
|
|
|
|
|
s := createTestServer(t)
|
|
|
|
|
startDeferStop(t, s)
|
2019-02-25 11:58:54 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
|
|
|
|
client := dns.Client{Net: proxy.ProtoUDP}
|
2019-02-25 11:58:54 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
exchangeAndAssertResponse(t, &client, addr, tc, testUpstreamIP)
|
|
|
|
|
})
|
2019-02-25 11:58:54 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-24 12:19:52 +00:00
|
|
|
|
func TestInvalidRequest(t *testing.T) {
|
2019-02-10 17:47:43 +00:00
|
|
|
|
s := createTestServer(t)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
2018-12-24 12:19:52 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP).String()
|
|
|
|
|
req := dns.Msg{
|
|
|
|
|
MsgHdr: dns.MsgHdr{
|
|
|
|
|
Id: dns.Id(),
|
|
|
|
|
RecursionDesired: true,
|
|
|
|
|
},
|
2018-12-24 12:19:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Send a DNS request without question.
|
|
|
|
|
_, _, err := (&dns.Client{
|
|
|
|
|
Net: proxy.ProtoUDP,
|
|
|
|
|
Timeout: 500 * time.Millisecond,
|
|
|
|
|
}).Exchange(&req, addr)
|
|
|
|
|
|
|
|
|
|
assert.Nil(t, err, "got a response to an invalid query")
|
2018-12-24 12:19:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestBlockedRequest(t *testing.T) {
|
2019-02-10 17:47:43 +00:00
|
|
|
|
s := createTestServer(t)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
|
|
|
|
|
2019-02-22 12:23:39 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
2018-12-24 12:19:52 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Default blocking.
|
|
|
|
|
req := createTestMessage("nxdomain.example.org.")
|
2018-12-24 12:19:52 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
reply, err := dns.Exchange(req, addr.String())
|
|
|
|
|
assert.Nilf(t, err, "couldn't talk to server %s: %s", addr, err)
|
2020-10-02 09:51:55 +00:00
|
|
|
|
assert.Equal(t, dns.RcodeSuccess, reply.Rcode)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.True(t, reply.Answer[0].(*dns.A).A.IsUnspecified())
|
2018-12-24 12:19:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 09:57:41 +00:00
|
|
|
|
func TestServerCustomClientUpstream(t *testing.T) {
|
|
|
|
|
s := createTestServer(t)
|
2020-12-17 10:32:46 +00:00
|
|
|
|
s.conf.GetCustomUpstreamByClient = func(_ string) *proxy.UpstreamConfig {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
return &proxy.UpstreamConfig{
|
|
|
|
|
Upstreams: []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
ipv4: map[string][]net.IP{
|
|
|
|
|
"host.": {{192, 168, 0, 1}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
2020-05-14 09:57:41 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
2020-08-13 08:49:42 +00:00
|
|
|
|
|
2020-05-14 09:57:41 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Send test request.
|
|
|
|
|
req := createTestMessage("host.")
|
2020-05-14 09:57:41 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
reply, err := dns.Exchange(req, addr.String())
|
2020-05-14 09:57:41 +00:00
|
|
|
|
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, dns.RcodeSuccess, reply.Rcode)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.NotEmpty(t, reply.Answer)
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, net.IP{192, 168, 0, 1}, reply.Answer[0].(*dns.A).A)
|
2020-05-14 09:57:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// testUpstream is a mock of real upstream. specify fields with necessary values
|
|
|
|
|
// to simulate real upstream behaviour.
|
|
|
|
|
//
|
|
|
|
|
// TODO(e.burkov): move into aghtest package.
|
2019-11-21 13:13:19 +00:00
|
|
|
|
type testUpstream struct {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// cn is a map of hostname to canonical name.
|
|
|
|
|
cn map[string]string
|
|
|
|
|
// ipv4 is a map of hostname to IPv4.
|
|
|
|
|
ipv4 map[string][]net.IP
|
|
|
|
|
// ipv6 is a map of hostname to IPv6.
|
|
|
|
|
ipv6 map[string][]net.IP
|
2019-11-21 13:13:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Exchange implements upstream.Upstream interface for *testUpstream.
|
2019-11-21 13:13:19 +00:00
|
|
|
|
func (u *testUpstream) Exchange(m *dns.Msg) (*dns.Msg, error) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
resp := &dns.Msg{}
|
2019-11-21 13:13:19 +00:00
|
|
|
|
resp.SetReply(m)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
hasRec := false
|
2019-11-21 13:13:19 +00:00
|
|
|
|
|
|
|
|
|
name := m.Question[0].Name
|
|
|
|
|
|
|
|
|
|
if cname, ok := u.cn[name]; ok {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
resp.Answer = append(resp.Answer, &dns.CNAME{
|
|
|
|
|
Hdr: dns.RR_Header{
|
|
|
|
|
Name: name,
|
|
|
|
|
Rrtype: dns.TypeCNAME,
|
|
|
|
|
},
|
|
|
|
|
Target: cname,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rrtype uint16
|
|
|
|
|
var a []net.IP
|
|
|
|
|
switch m.Question[0].Qtype {
|
|
|
|
|
case dns.TypeA:
|
|
|
|
|
rrtype = dns.TypeA
|
|
|
|
|
if ipv4addr, ok := u.ipv4[name]; ok {
|
|
|
|
|
hasRec = true
|
|
|
|
|
a = ipv4addr
|
2019-11-21 13:13:19 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
case dns.TypeAAAA:
|
|
|
|
|
rrtype = dns.TypeAAAA
|
|
|
|
|
if ipv6addr, ok := u.ipv6[name]; ok {
|
|
|
|
|
hasRec = true
|
|
|
|
|
a = ipv6addr
|
2019-11-21 13:13:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
for _, ip := range a {
|
|
|
|
|
resp.Answer = append(resp.Answer, &dns.A{
|
|
|
|
|
Hdr: dns.RR_Header{
|
|
|
|
|
Name: name,
|
|
|
|
|
Rrtype: rrtype,
|
|
|
|
|
},
|
|
|
|
|
A: ip,
|
|
|
|
|
})
|
|
|
|
|
}
|
2019-11-21 13:13:19 +00:00
|
|
|
|
|
|
|
|
|
if len(resp.Answer) == 0 {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
if hasRec {
|
|
|
|
|
// Set no error RCode if there are some records for
|
|
|
|
|
// given Qname but we didn't apply them.
|
2019-11-21 13:13:19 +00:00
|
|
|
|
resp.SetRcode(m, dns.RcodeSuccess)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
return resp, nil
|
2019-11-21 13:13:19 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Set NXDomain RCode otherwise.
|
|
|
|
|
resp.SetRcode(m, dns.RcodeNameError)
|
2019-11-21 13:13:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
return resp, nil
|
2019-11-21 13:13:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Address implements upstream.Upstream interface for *testUpstream.
|
2019-11-21 13:13:19 +00:00
|
|
|
|
func (u *testUpstream) Address() string {
|
|
|
|
|
return "test"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) startWithUpstream(u upstream.Upstream) error {
|
|
|
|
|
s.Lock()
|
|
|
|
|
defer s.Unlock()
|
2019-12-11 09:38:58 +00:00
|
|
|
|
err := s.Prepare(nil)
|
2019-11-21 13:13:19 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-05-13 17:31:43 +00:00
|
|
|
|
s.dnsProxy.UpstreamConfig = &proxy.UpstreamConfig{
|
|
|
|
|
Upstreams: []upstream.Upstream{u},
|
|
|
|
|
}
|
2019-11-21 13:13:19 +00:00
|
|
|
|
return s.dnsProxy.Start()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// testCNAMEs is a simple map of names and CNAMEs necessary for the testUpstream work
|
|
|
|
|
var testCNAMEs = map[string]string{
|
|
|
|
|
"badhost.": "null.example.org.",
|
|
|
|
|
"whitelist.example.org.": "null.example.org.",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// testIPv4 is a simple map of names and IPv4s necessary for the testUpstream work
|
|
|
|
|
var testIPv4 = map[string][]net.IP{
|
|
|
|
|
"null.example.org.": {{1, 2, 3, 4}},
|
|
|
|
|
"example.org.": {{127, 0, 0, 255}},
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 16:52:06 +00:00
|
|
|
|
func TestBlockCNAMEProtectionEnabled(t *testing.T) {
|
|
|
|
|
s := createTestServer(t)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
testUpstm := &testUpstream{
|
|
|
|
|
cn: testCNAMEs,
|
|
|
|
|
ipv4: testIPv4,
|
|
|
|
|
ipv6: nil,
|
|
|
|
|
}
|
2020-01-09 16:52:06 +00:00
|
|
|
|
s.conf.ProtectionEnabled = false
|
|
|
|
|
err := s.startWithUpstream(testUpstm)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Nil(t, err)
|
2020-01-09 16:52:06 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// 'badhost' has a canonical name 'null.example.org' which is blocked by
|
|
|
|
|
// filters: but protection is disabled so response is _not_ blocked.
|
2020-01-09 16:52:06 +00:00
|
|
|
|
req := createTestMessage("badhost.")
|
|
|
|
|
reply, err := dns.Exchange(req, addr.String())
|
2020-05-13 17:31:43 +00:00
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, dns.RcodeSuccess, reply.Rcode)
|
2020-01-09 16:52:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-21 13:13:19 +00:00
|
|
|
|
func TestBlockCNAME(t *testing.T) {
|
|
|
|
|
s := createTestServer(t)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
cn: testCNAMEs,
|
|
|
|
|
ipv4: testIPv4,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
startDeferStop(t, s)
|
|
|
|
|
|
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP).String()
|
|
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
|
host string
|
|
|
|
|
want bool
|
|
|
|
|
}{{
|
|
|
|
|
host: "badhost.",
|
|
|
|
|
// 'badhost' has a canonical name 'null.example.org' which is
|
|
|
|
|
// blocked by filters: response is blocked.
|
|
|
|
|
want: true,
|
|
|
|
|
}, {
|
|
|
|
|
host: "whitelist.example.org.",
|
|
|
|
|
// 'whitelist.example.org' has a canonical name
|
|
|
|
|
// 'null.example.org' which is blocked by filters
|
|
|
|
|
// but 'whitelist.example.org' is in a whitelist:
|
|
|
|
|
// response isn't blocked.
|
|
|
|
|
want: false,
|
|
|
|
|
}, {
|
|
|
|
|
host: "example.org.",
|
|
|
|
|
// 'example.org' has a canonical name 'cname1' with IP
|
|
|
|
|
// 127.0.0.255 which is blocked by filters: response is blocked.
|
|
|
|
|
want: true,
|
|
|
|
|
}}
|
2019-11-21 13:13:19 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
for _, tc := range testCases {
|
|
|
|
|
t.Run("block_cname_"+tc.host, func(t *testing.T) {
|
|
|
|
|
req := createTestMessage(tc.host)
|
|
|
|
|
reply, err := dns.Exchange(req, addr)
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, dns.RcodeSuccess, reply.Rcode)
|
|
|
|
|
if tc.want {
|
|
|
|
|
assert.True(t, reply.Answer[0].(*dns.A).A.IsUnspecified())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
2019-11-21 13:13:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-23 10:36:59 +00:00
|
|
|
|
func TestClientRulesForCNAMEMatching(t *testing.T) {
|
|
|
|
|
s := createTestServer(t)
|
2021-01-27 15:32:13 +00:00
|
|
|
|
s.conf.FilterHandler = func(_ net.IP, _ string, settings *dnsfilter.RequestFilteringSettings) {
|
2019-12-23 10:36:59 +00:00
|
|
|
|
settings.FilteringEnabled = false
|
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
cn: testCNAMEs,
|
|
|
|
|
ipv4: testIPv4,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
startDeferStop(t, s)
|
|
|
|
|
|
2019-12-23 10:36:59 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// 'badhost' has a canonical name 'null.example.org' which is blocked by
|
|
|
|
|
// filters: response is blocked.
|
|
|
|
|
req := dns.Msg{
|
|
|
|
|
MsgHdr: dns.MsgHdr{
|
|
|
|
|
Id: dns.Id(),
|
|
|
|
|
},
|
|
|
|
|
Question: []dns.Question{{
|
|
|
|
|
Name: "badhost.",
|
|
|
|
|
Qtype: dns.TypeA,
|
|
|
|
|
Qclass: dns.ClassINET,
|
|
|
|
|
}},
|
2019-12-23 10:36:59 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
|
|
|
|
|
// However, in our case it should not be blocked as filtering is
|
|
|
|
|
// disabled on the client level.
|
2019-12-23 10:36:59 +00:00
|
|
|
|
reply, err := dns.Exchange(&req, addr.String())
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, dns.RcodeSuccess, reply.Rcode)
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 12:53:31 +00:00
|
|
|
|
func TestNullBlockedRequest(t *testing.T) {
|
|
|
|
|
s := createTestServer(t)
|
2019-05-15 12:08:15 +00:00
|
|
|
|
s.conf.FilteringConfig.BlockingMode = "null_ip"
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
2019-05-14 12:53:31 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Nil filter blocking.
|
|
|
|
|
req := dns.Msg{
|
|
|
|
|
MsgHdr: dns.MsgHdr{
|
|
|
|
|
Id: dns.Id(),
|
|
|
|
|
RecursionDesired: true,
|
|
|
|
|
},
|
|
|
|
|
Question: []dns.Question{{
|
|
|
|
|
Name: "null.example.org.",
|
|
|
|
|
Qtype: dns.TypeA,
|
|
|
|
|
Qclass: dns.ClassINET,
|
|
|
|
|
}},
|
2019-05-14 12:53:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reply, err := dns.Exchange(&req, addr.String())
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "couldn't talk to server %s: %s", addr, err)
|
|
|
|
|
assert.Lenf(t, reply.Answer, 1, "dns server %s returned reply with wrong number of answers - %d", addr, len(reply.Answer))
|
|
|
|
|
a, ok := reply.Answer[0].(*dns.A)
|
|
|
|
|
assert.Truef(t, ok, "dns server %s returned wrong answer type instead of A: %v", addr, reply.Answer[0])
|
|
|
|
|
assert.Truef(t, a.A.IsUnspecified(), "dns server %s returned wrong answer instead of 0.0.0.0: %v", addr, a.A)
|
2019-05-14 12:53:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-16 14:04:30 +00:00
|
|
|
|
func TestBlockedCustomIP(t *testing.T) {
|
|
|
|
|
rules := "||nxdomain.example.org^\n||null.example.org^\n127.0.0.1 host.example.org\n@@||whitelist.example.org^\n||127.0.0.255\n"
|
2020-05-13 17:31:43 +00:00
|
|
|
|
filters := []dnsfilter.Filter{{
|
2021-02-02 12:13:12 +00:00
|
|
|
|
ID: 0,
|
|
|
|
|
Data: []byte(rules),
|
2020-02-26 16:58:25 +00:00
|
|
|
|
}}
|
2019-12-16 14:04:30 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s := NewServer(DNSCreateParams{
|
|
|
|
|
DNSFilter: dnsfilter.New(&dnsfilter.Config{}, filters),
|
|
|
|
|
})
|
|
|
|
|
conf := ServerConfig{
|
|
|
|
|
UDPListenAddr: &net.UDPAddr{Port: 0},
|
|
|
|
|
TCPListenAddr: &net.TCPAddr{Port: 0},
|
|
|
|
|
FilteringConfig: FilteringConfig{
|
|
|
|
|
ProtectionEnabled: true,
|
|
|
|
|
BlockingMode: "custom_ip",
|
|
|
|
|
BlockingIPv4: nil,
|
|
|
|
|
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
// Invalid BlockingIPv4.
|
|
|
|
|
assert.NotNil(t, s.Prepare(&conf))
|
2019-12-16 14:04:30 +00:00
|
|
|
|
|
2021-01-13 13:56:05 +00:00
|
|
|
|
conf.BlockingIPv4 = net.IP{0, 0, 0, 1}
|
|
|
|
|
conf.BlockingIPv6 = net.ParseIP("::1")
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nil(t, s.Prepare(&conf))
|
|
|
|
|
|
|
|
|
|
startDeferStop(t, s)
|
2019-12-16 14:04:30 +00:00
|
|
|
|
|
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
|
|
|
|
|
|
|
|
|
req := createTestMessageWithType("null.example.org.", dns.TypeA)
|
|
|
|
|
reply, err := dns.Exchange(req, addr.String())
|
2020-05-13 17:31:43 +00:00
|
|
|
|
assert.Nil(t, err)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Len(t, reply.Answer, 1)
|
2019-12-16 14:04:30 +00:00
|
|
|
|
a, ok := reply.Answer[0].(*dns.A)
|
|
|
|
|
assert.True(t, ok)
|
2021-01-20 14:27:53 +00:00
|
|
|
|
assert.True(t, net.IP{0, 0, 0, 1}.Equal(a.A))
|
2019-12-16 14:04:30 +00:00
|
|
|
|
|
|
|
|
|
req = createTestMessageWithType("null.example.org.", dns.TypeAAAA)
|
|
|
|
|
reply, err = dns.Exchange(req, addr.String())
|
2020-05-13 17:31:43 +00:00
|
|
|
|
assert.Nil(t, err)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Len(t, reply.Answer, 1)
|
2019-12-16 14:04:30 +00:00
|
|
|
|
a6, ok := reply.Answer[0].(*dns.AAAA)
|
|
|
|
|
assert.True(t, ok)
|
2020-05-13 17:31:43 +00:00
|
|
|
|
assert.Equal(t, "::1", a6.AAAA.String())
|
2019-12-16 14:04:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-24 12:19:52 +00:00
|
|
|
|
func TestBlockedByHosts(t *testing.T) {
|
2019-02-10 17:47:43 +00:00
|
|
|
|
s := createTestServer(t)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
2018-12-24 12:19:52 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Hosts blocking.
|
|
|
|
|
req := createTestMessage("host.example.org.")
|
2018-12-24 12:19:52 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
reply, err := dns.Exchange(req, addr.String())
|
|
|
|
|
assert.Nilf(t, err, "couldn't talk to server %s: %s", addr, err)
|
|
|
|
|
assert.Lenf(t, reply.Answer, 1, "dns server %s returned reply with wrong number of answers - %d", addr, len(reply.Answer))
|
2018-12-24 12:19:52 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
a, ok := reply.Answer[0].(*dns.A)
|
|
|
|
|
assert.Truef(t, ok, "dns server %s returned wrong answer type instead of A: %v", addr, reply.Answer[0])
|
|
|
|
|
assert.Equalf(t, net.IP{127, 0, 0, 1}, a.A, "dns server %s returned wrong answer instead of 8.8.8.8: %v", addr, a.A)
|
2018-12-24 12:19:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestBlockedBySafeBrowsing(t *testing.T) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
t.Skip("TODO(e.burkov): substitute the dnsfilter by one with custom safeBrowsingUpstream")
|
|
|
|
|
resolver := &testResolver{}
|
|
|
|
|
ips, _ := resolver.LookupIPAddr(context.Background(), safeBrowsingBlockHost)
|
|
|
|
|
addrs, _ := resolver.LookupHost(safeBrowsingBlockHost)
|
|
|
|
|
|
2019-02-10 17:47:43 +00:00
|
|
|
|
s := createTestServer(t)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
ipv4: map[string][]net.IP{
|
|
|
|
|
"wmconvirus.narod.ru.": {ips[0].IP},
|
|
|
|
|
},
|
|
|
|
|
},
|
2018-12-24 12:19:52 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
2018-12-24 12:19:52 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// SafeBrowsing blocking.
|
|
|
|
|
req := createTestMessage("wmconvirus.narod.ru.")
|
|
|
|
|
|
|
|
|
|
reply, err := dns.Exchange(req, addr.String())
|
|
|
|
|
assert.Nilf(t, err, "couldn't talk to server %s: %s", addr, err)
|
|
|
|
|
assert.Lenf(t, reply.Answer, 1, "dns server %s returned reply with wrong number of answers - %d", addr, len(reply.Answer))
|
2018-12-24 12:19:52 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
a, ok := reply.Answer[0].(*dns.A)
|
|
|
|
|
if assert.Truef(t, ok, "dns server %s returned wrong answer type instead of A: %v", addr, reply.Answer[0]) {
|
2018-12-24 12:19:52 +00:00
|
|
|
|
found := false
|
|
|
|
|
for _, blockAddr := range addrs {
|
|
|
|
|
if blockAddr == a.A.String() {
|
|
|
|
|
found = true
|
2021-02-02 12:13:12 +00:00
|
|
|
|
break
|
2018-12-24 12:19:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Truef(t, found, "dns server %s returned wrong answer: %v", addr, a.A)
|
2018-12-24 12:19:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-01 12:23:08 +00:00
|
|
|
|
func TestRewrite(t *testing.T) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
c := &dnsfilter.Config{
|
|
|
|
|
Rewrites: []dnsfilter.RewriteEntry{{
|
2020-06-01 12:23:08 +00:00
|
|
|
|
Domain: "test.com",
|
|
|
|
|
Answer: "1.2.3.4",
|
|
|
|
|
Type: dns.TypeA,
|
2021-02-02 12:13:12 +00:00
|
|
|
|
}, {
|
2020-06-01 12:23:08 +00:00
|
|
|
|
Domain: "alias.test.com",
|
|
|
|
|
Answer: "test.com",
|
|
|
|
|
Type: dns.TypeCNAME,
|
2021-02-02 12:13:12 +00:00
|
|
|
|
}, {
|
2020-06-01 12:23:08 +00:00
|
|
|
|
Domain: "my.alias.example.org",
|
|
|
|
|
Answer: "example.org",
|
|
|
|
|
Type: dns.TypeCNAME,
|
2021-02-02 12:13:12 +00:00
|
|
|
|
}},
|
2020-06-01 12:23:08 +00:00
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
f := dnsfilter.New(c, nil)
|
2020-06-01 12:23:08 +00:00
|
|
|
|
|
2020-06-23 09:13:13 +00:00
|
|
|
|
s := NewServer(DNSCreateParams{DNSFilter: f})
|
2021-02-02 12:13:12 +00:00
|
|
|
|
err := s.Prepare(&ServerConfig{
|
|
|
|
|
UDPListenAddr: &net.UDPAddr{Port: 0},
|
|
|
|
|
TCPListenAddr: &net.TCPAddr{Port: 0},
|
|
|
|
|
FilteringConfig: FilteringConfig{
|
|
|
|
|
ProtectionEnabled: true,
|
|
|
|
|
UpstreamDNS: []string{"8.8.8.8:53"},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
|
|
|
|
|
&testUpstream{
|
|
|
|
|
cn: map[string]string{
|
|
|
|
|
"example.org": "somename",
|
|
|
|
|
},
|
|
|
|
|
ipv4: map[string][]net.IP{
|
|
|
|
|
"example.org.": {{4, 3, 2, 1}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
2020-06-01 12:23:08 +00:00
|
|
|
|
assert.Nil(t, err)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
startDeferStop(t, s)
|
|
|
|
|
|
2020-06-01 12:23:08 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
|
|
|
|
|
|
|
|
|
req := createTestMessageWithType("test.com.", dns.TypeA)
|
|
|
|
|
reply, err := dns.Exchange(req, addr.String())
|
|
|
|
|
assert.Nil(t, err)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Len(t, reply.Answer, 1)
|
2020-06-01 12:23:08 +00:00
|
|
|
|
a, ok := reply.Answer[0].(*dns.A)
|
|
|
|
|
assert.True(t, ok)
|
2021-01-20 14:27:53 +00:00
|
|
|
|
assert.True(t, net.IP{1, 2, 3, 4}.Equal(a.A))
|
2020-06-01 12:23:08 +00:00
|
|
|
|
|
2020-07-24 10:27:14 +00:00
|
|
|
|
req = createTestMessageWithType("test.com.", dns.TypeAAAA)
|
|
|
|
|
reply, err = dns.Exchange(req, addr.String())
|
|
|
|
|
assert.Nil(t, err)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Empty(t, reply.Answer)
|
2020-07-24 10:27:14 +00:00
|
|
|
|
|
2020-06-01 12:23:08 +00:00
|
|
|
|
req = createTestMessageWithType("alias.test.com.", dns.TypeA)
|
|
|
|
|
reply, err = dns.Exchange(req, addr.String())
|
|
|
|
|
assert.Nil(t, err)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Len(t, reply.Answer, 2)
|
2020-06-01 12:23:08 +00:00
|
|
|
|
assert.Equal(t, "test.com.", reply.Answer[0].(*dns.CNAME).Target)
|
2021-01-20 14:27:53 +00:00
|
|
|
|
assert.True(t, net.IP{1, 2, 3, 4}.Equal(reply.Answer[1].(*dns.A).A))
|
2020-06-01 12:23:08 +00:00
|
|
|
|
|
|
|
|
|
req = createTestMessageWithType("my.alias.example.org.", dns.TypeA)
|
|
|
|
|
reply, err = dns.Exchange(req, addr.String())
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, "my.alias.example.org.", reply.Question[0].Name) // the original question is restored
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Len(t, reply.Answer, 2)
|
2020-06-01 12:23:08 +00:00
|
|
|
|
assert.Equal(t, "example.org.", reply.Answer[0].(*dns.CNAME).Target)
|
|
|
|
|
assert.Equal(t, dns.TypeA, reply.Answer[1].Header().Rrtype)
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-10 17:47:43 +00:00
|
|
|
|
func createTestServer(t *testing.T) *Server {
|
2019-12-23 10:36:59 +00:00
|
|
|
|
rules := `||nxdomain.example.org
|
|
|
|
|
||null.example.org^
|
|
|
|
|
127.0.0.1 host.example.org
|
|
|
|
|
@@||whitelist.example.org^
|
|
|
|
|
||127.0.0.255`
|
2020-05-13 17:31:43 +00:00
|
|
|
|
filters := []dnsfilter.Filter{{
|
2020-02-26 16:58:25 +00:00
|
|
|
|
ID: 0, Data: []byte(rules),
|
|
|
|
|
}}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
c := dnsfilter.Config{
|
|
|
|
|
SafeBrowsingEnabled: true,
|
|
|
|
|
SafeBrowsingCacheSize: 1000,
|
|
|
|
|
SafeSearchEnabled: true,
|
|
|
|
|
SafeSearchCacheSize: 1000,
|
|
|
|
|
ParentalCacheSize: 1000,
|
|
|
|
|
CacheTime: 30,
|
|
|
|
|
}
|
2019-10-09 16:51:26 +00:00
|
|
|
|
|
|
|
|
|
f := dnsfilter.New(&c, filters)
|
2020-11-16 16:45:31 +00:00
|
|
|
|
|
2020-06-23 09:13:13 +00:00
|
|
|
|
s := NewServer(DNSCreateParams{DNSFilter: f})
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s.conf = ServerConfig{
|
|
|
|
|
UDPListenAddr: &net.UDPAddr{Port: 0},
|
|
|
|
|
TCPListenAddr: &net.TCPAddr{Port: 0},
|
|
|
|
|
FilteringConfig: FilteringConfig{
|
|
|
|
|
ProtectionEnabled: true,
|
|
|
|
|
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
|
|
|
|
},
|
|
|
|
|
ConfigModified: func() {},
|
|
|
|
|
}
|
2020-11-16 16:45:31 +00:00
|
|
|
|
|
2019-12-11 09:38:58 +00:00
|
|
|
|
err := s.Prepare(nil)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Nil(t, err)
|
2019-02-10 17:47:43 +00:00
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-22 12:23:39 +00:00
|
|
|
|
func createServerTLSConfig(t *testing.T) (*tls.Config, []byte, []byte) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
t.Helper()
|
|
|
|
|
|
2019-02-22 12:23:39 +00:00
|
|
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "cannot generate RSA key: %s", err)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
|
|
|
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
|
|
|
|
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "failed to generate serial number: %s", err)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
|
|
|
|
notBefore := time.Now()
|
|
|
|
|
notAfter := notBefore.Add(5 * 365 * time.Hour * 24)
|
|
|
|
|
|
|
|
|
|
template := x509.Certificate{
|
|
|
|
|
SerialNumber: serialNumber,
|
|
|
|
|
Subject: pkix.Name{
|
|
|
|
|
Organization: []string{"AdGuard Tests"},
|
|
|
|
|
},
|
|
|
|
|
NotBefore: notBefore,
|
|
|
|
|
NotAfter: notAfter,
|
|
|
|
|
|
|
|
|
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
|
|
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
|
|
|
BasicConstraintsValid: true,
|
|
|
|
|
IsCA: true,
|
|
|
|
|
}
|
|
|
|
|
template.DNSNames = append(template.DNSNames, tlsServerName)
|
|
|
|
|
|
|
|
|
|
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "failed to create certificate: %s", err)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
|
|
|
|
certPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
|
|
|
|
keyPem := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)})
|
|
|
|
|
|
|
|
|
|
cert, err := tls.X509KeyPair(certPem, keyPem)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "failed to create certificate: %s", err)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
return &tls.Config{
|
|
|
|
|
Certificates: []tls.Certificate{cert},
|
|
|
|
|
ServerName: tlsServerName,
|
|
|
|
|
MinVersion: tls.VersionTLS12,
|
|
|
|
|
}, certPem, keyPem
|
2019-02-22 12:23:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// sendTestMessagesAsync sends messages in parallel to check for race issues.
|
|
|
|
|
//lint:ignore U1000 it's called from the function which is skipped for now.
|
|
|
|
|
func sendTestMessagesAsync(t *testing.T, conn *dns.Conn) {
|
|
|
|
|
wg := &sync.WaitGroup{}
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
for i := 0; i < testMessagesCount; i++ {
|
|
|
|
|
msg := createGoogleATestMessage()
|
|
|
|
|
wg.Add(1)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
go func() {
|
|
|
|
|
defer wg.Done()
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
err := conn.WriteMsg(msg)
|
|
|
|
|
assert.Nilf(t, err, "cannot write message: %s", err)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
res, err := conn.ReadMsg()
|
|
|
|
|
assert.Nilf(t, err, "cannot read response to message: %s", err)
|
|
|
|
|
|
|
|
|
|
assertGoogleAResponse(t, res)
|
|
|
|
|
}()
|
2019-02-22 12:23:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
wg.Wait()
|
2019-02-22 12:23:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func sendTestMessages(t *testing.T, conn *dns.Conn) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
for i := 0; i < testMessagesCount; i++ {
|
2019-02-25 14:07:26 +00:00
|
|
|
|
req := createGoogleATestMessage()
|
2019-02-22 12:23:39 +00:00
|
|
|
|
err := conn.WriteMsg(req)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "cannot write message #%d: %s", i, err)
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
|
|
|
|
res, err := conn.ReadMsg()
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "cannot read response to message #%d: %s", i, err)
|
2019-02-25 14:07:26 +00:00
|
|
|
|
assertGoogleAResponse(t, res)
|
2019-02-10 17:47:43 +00:00
|
|
|
|
}
|
2018-12-05 17:13:35 +00:00
|
|
|
|
}
|
2019-01-05 19:15:20 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
func exchangeAndAssertResponse(t *testing.T, client *dns.Client, addr net.Addr, host string, ip net.IP) {
|
2020-12-17 10:32:46 +00:00
|
|
|
|
t.Helper()
|
|
|
|
|
|
2019-02-25 11:58:54 +00:00
|
|
|
|
req := createTestMessage(host)
|
|
|
|
|
reply, _, err := client.Exchange(req, addr.String())
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nilf(t, err, "couldn't talk to server %s: %s", addr, err)
|
2019-02-25 11:58:54 +00:00
|
|
|
|
assertResponse(t, reply, ip)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func createGoogleATestMessage() *dns.Msg {
|
|
|
|
|
return createTestMessage("google-public-dns-a.google.com.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func createTestMessage(host string) *dns.Msg {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
return &dns.Msg{
|
|
|
|
|
MsgHdr: dns.MsgHdr{
|
|
|
|
|
Id: dns.Id(),
|
|
|
|
|
RecursionDesired: true,
|
|
|
|
|
},
|
|
|
|
|
Question: []dns.Question{{
|
|
|
|
|
Name: host,
|
|
|
|
|
Qtype: dns.TypeA,
|
|
|
|
|
Qclass: dns.ClassINET,
|
|
|
|
|
}},
|
2019-01-05 19:15:20 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-16 14:04:30 +00:00
|
|
|
|
func createTestMessageWithType(host string, qtype uint16) *dns.Msg {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
req := createTestMessage(host)
|
|
|
|
|
req.Question[0].Qtype = qtype
|
|
|
|
|
return req
|
2019-12-16 14:04:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-25 11:58:54 +00:00
|
|
|
|
func assertGoogleAResponse(t *testing.T, reply *dns.Msg) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assertResponse(t, reply, net.IP{8, 8, 8, 8})
|
2019-02-25 11:58:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
func assertResponse(t *testing.T, reply *dns.Msg, ip net.IP) {
|
2020-12-17 10:32:46 +00:00
|
|
|
|
t.Helper()
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Lenf(t, reply.Answer, 1, "dns server returned reply with wrong number of answers - %d", len(reply.Answer))
|
|
|
|
|
a, ok := reply.Answer[0].(*dns.A)
|
|
|
|
|
if assert.Truef(t, ok, "dns server returned wrong answer type instead of A: %v", reply.Answer[0]) {
|
|
|
|
|
assert.Truef(t, a.A.Equal(ip), "dns server returned wrong answer instead of %s: %s", ip, a.A)
|
2019-01-05 19:15:20 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-22 12:23:39 +00:00
|
|
|
|
|
|
|
|
|
func publicKey(priv interface{}) interface{} {
|
|
|
|
|
switch k := priv.(type) {
|
|
|
|
|
case *rsa.PrivateKey:
|
|
|
|
|
return &k.PublicKey
|
|
|
|
|
case *ecdsa.PrivateKey:
|
|
|
|
|
return &k.PublicKey
|
|
|
|
|
default:
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-24 11:49:26 +00:00
|
|
|
|
|
2019-10-30 14:23:13 +00:00
|
|
|
|
func TestValidateUpstream(t *testing.T) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
testCases := []struct {
|
|
|
|
|
name string
|
|
|
|
|
upstream string
|
|
|
|
|
valid bool
|
|
|
|
|
wantDef bool
|
|
|
|
|
}{{
|
|
|
|
|
name: "invalid",
|
|
|
|
|
upstream: "1.2.3.4.5",
|
|
|
|
|
valid: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "invalid",
|
|
|
|
|
upstream: "123.3.7m",
|
|
|
|
|
valid: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "invalid",
|
|
|
|
|
upstream: "htttps://google.com/dns-query",
|
|
|
|
|
valid: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "invalid",
|
|
|
|
|
upstream: "[/host.com]tls://dns.adguard.com",
|
|
|
|
|
valid: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "invalid",
|
|
|
|
|
upstream: "[host.ru]#",
|
|
|
|
|
valid: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "valid_default",
|
|
|
|
|
upstream: "1.1.1.1",
|
|
|
|
|
valid: true,
|
|
|
|
|
wantDef: true,
|
|
|
|
|
}, {
|
|
|
|
|
name: "valid_default",
|
|
|
|
|
upstream: "tls://1.1.1.1",
|
|
|
|
|
valid: true,
|
|
|
|
|
wantDef: true,
|
|
|
|
|
}, {
|
|
|
|
|
name: "valid_default",
|
|
|
|
|
upstream: "https://dns.adguard.com/dns-query",
|
|
|
|
|
valid: true,
|
|
|
|
|
wantDef: true,
|
|
|
|
|
}, {
|
|
|
|
|
name: "valid_default",
|
|
|
|
|
upstream: "sdns://AQMAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20",
|
|
|
|
|
valid: true,
|
|
|
|
|
wantDef: true,
|
|
|
|
|
}, {
|
|
|
|
|
name: "valid",
|
|
|
|
|
upstream: "[/host.com/]1.1.1.1",
|
|
|
|
|
valid: true,
|
|
|
|
|
wantDef: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "valid",
|
|
|
|
|
upstream: "[//]tls://1.1.1.1",
|
|
|
|
|
valid: true,
|
|
|
|
|
wantDef: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "valid",
|
|
|
|
|
upstream: "[/www.host.com/]#",
|
|
|
|
|
valid: true,
|
|
|
|
|
wantDef: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "valid",
|
|
|
|
|
upstream: "[/host.com/google.com/]8.8.8.8",
|
|
|
|
|
valid: true,
|
|
|
|
|
wantDef: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "valid",
|
|
|
|
|
upstream: "[/host/]sdns://AQMAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20",
|
|
|
|
|
valid: true,
|
|
|
|
|
wantDef: false,
|
|
|
|
|
}}
|
2019-10-30 14:23:13 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
for _, tc := range testCases {
|
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
|
defaultUpstream, err := validateUpstream(tc.upstream)
|
|
|
|
|
assert.Equal(t, tc.valid, err == nil)
|
|
|
|
|
if err == nil {
|
|
|
|
|
assert.Equal(t, tc.wantDef, defaultUpstream)
|
|
|
|
|
}
|
|
|
|
|
})
|
2019-05-24 11:49:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-30 14:23:13 +00:00
|
|
|
|
func TestValidateUpstreamsSet(t *testing.T) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Empty upstreams array.
|
2020-09-22 12:04:17 +00:00
|
|
|
|
var upstreamsSet []string
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nil(t, ValidateUpstreams(upstreamsSet), "empty upstreams array should be valid")
|
2020-09-22 12:04:17 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Comment in upstreams array.
|
2020-09-22 12:04:17 +00:00
|
|
|
|
upstreamsSet = []string{"# comment"}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nil(t, ValidateUpstreams(upstreamsSet), "comments should not be validated")
|
2020-09-22 12:04:17 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Set of valid upstreams. There is no default upstream specified.
|
2020-11-03 12:39:55 +00:00
|
|
|
|
upstreamsSet = []string{
|
|
|
|
|
"[/host.com/]1.1.1.1",
|
2019-10-30 14:23:13 +00:00
|
|
|
|
"[//]tls://1.1.1.1",
|
|
|
|
|
"[/www.host.com/]#",
|
|
|
|
|
"[/host.com/google.com/]8.8.8.8",
|
|
|
|
|
"[/host/]sdns://AQMAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20",
|
|
|
|
|
}
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.NotNil(t, ValidateUpstreams(upstreamsSet), "there is no default upstream")
|
2019-05-24 11:49:26 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Let's add default upstream.
|
2019-10-30 14:23:13 +00:00
|
|
|
|
upstreamsSet = append(upstreamsSet, "8.8.8.8")
|
2021-02-02 12:13:12 +00:00
|
|
|
|
err := ValidateUpstreams(upstreamsSet)
|
2020-09-22 12:04:17 +00:00
|
|
|
|
assert.Nilf(t, err, "upstreams set is valid, but doesn't pass through validation cause: %s", err)
|
2019-05-24 11:49:26 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Let's add invalid upstream.
|
2019-10-30 14:23:13 +00:00
|
|
|
|
upstreamsSet = append(upstreamsSet, "dhcp://fake.dns")
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.NotNil(t, ValidateUpstreams(upstreamsSet), "there is an invalid upstream in set, but it pass through validation")
|
2019-05-24 11:49:26 +00:00
|
|
|
|
}
|
2019-12-16 09:36:52 +00:00
|
|
|
|
|
2021-01-13 13:56:05 +00:00
|
|
|
|
func TestIPStringFromAddr(t *testing.T) {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
addr := net.UDPAddr{
|
|
|
|
|
IP: net.ParseIP("1:2:3::4"),
|
|
|
|
|
Port: 12345,
|
|
|
|
|
Zone: "eth0",
|
|
|
|
|
}
|
|
|
|
|
assert.Equal(t, IPStringFromAddr(&addr), addr.IP.String())
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Empty(t, IPStringFromAddr(nil))
|
2019-12-16 09:36:52 +00:00
|
|
|
|
}
|
2020-01-22 15:40:43 +00:00
|
|
|
|
|
|
|
|
|
func TestMatchDNSName(t *testing.T) {
|
|
|
|
|
dnsNames := []string{"host1", "*.host2", "1.2.3.4"}
|
|
|
|
|
sort.Strings(dnsNames)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
|
name string
|
|
|
|
|
dnsName string
|
|
|
|
|
want bool
|
|
|
|
|
}{{
|
|
|
|
|
name: "match",
|
|
|
|
|
dnsName: "host1",
|
|
|
|
|
want: true,
|
|
|
|
|
}, {
|
|
|
|
|
name: "match",
|
|
|
|
|
dnsName: "a.host2",
|
|
|
|
|
want: true,
|
|
|
|
|
}, {
|
|
|
|
|
name: "match",
|
|
|
|
|
dnsName: "b.a.host2",
|
|
|
|
|
want: true,
|
|
|
|
|
}, {
|
|
|
|
|
name: "match",
|
|
|
|
|
dnsName: "1.2.3.4",
|
|
|
|
|
want: true,
|
|
|
|
|
}, {
|
|
|
|
|
name: "mismatch",
|
|
|
|
|
dnsName: "host2",
|
|
|
|
|
want: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "mismatch",
|
|
|
|
|
dnsName: "",
|
|
|
|
|
want: false,
|
|
|
|
|
}, {
|
|
|
|
|
name: "mismatch",
|
|
|
|
|
dnsName: "*.host2",
|
|
|
|
|
want: false,
|
|
|
|
|
}}
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
|
assert.Equal(t, tc.want, matchDNSName(dnsNames, tc.dnsName))
|
|
|
|
|
})
|
|
|
|
|
}
|
2020-01-22 15:40:43 +00:00
|
|
|
|
}
|
2020-06-23 09:13:13 +00:00
|
|
|
|
|
2021-01-27 15:32:13 +00:00
|
|
|
|
type testDHCP struct{}
|
2020-07-03 15:20:01 +00:00
|
|
|
|
|
|
|
|
|
func (d *testDHCP) Leases(flags int) []dhcpd.Lease {
|
2021-02-02 12:13:12 +00:00
|
|
|
|
l := dhcpd.Lease{
|
|
|
|
|
IP: net.IP{127, 0, 0, 1},
|
|
|
|
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
|
|
|
|
Hostname: "localhost",
|
|
|
|
|
}
|
2020-07-03 15:20:01 +00:00
|
|
|
|
return []dhcpd.Lease{l}
|
|
|
|
|
}
|
2020-11-03 12:39:55 +00:00
|
|
|
|
func (d *testDHCP) SetOnLeaseChanged(onLeaseChanged dhcpd.OnLeaseChangedT) {}
|
2020-07-03 15:20:01 +00:00
|
|
|
|
|
2020-09-11 08:53:36 +00:00
|
|
|
|
func TestPTRResponseFromDHCPLeases(t *testing.T) {
|
2020-07-03 15:20:01 +00:00
|
|
|
|
dhcp := &testDHCP{}
|
2020-06-23 09:13:13 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s := NewServer(DNSCreateParams{
|
|
|
|
|
DNSFilter: dnsfilter.New(&dnsfilter.Config{}, nil),
|
|
|
|
|
DHCPServer: dhcp,
|
|
|
|
|
})
|
|
|
|
|
|
2020-06-23 09:13:13 +00:00
|
|
|
|
s.conf.UDPListenAddr = &net.UDPAddr{Port: 0}
|
|
|
|
|
s.conf.TCPListenAddr = &net.TCPAddr{Port: 0}
|
|
|
|
|
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
|
|
|
|
|
s.conf.FilteringConfig.ProtectionEnabled = true
|
|
|
|
|
err := s.Prepare(nil)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Nil(t, err)
|
2020-06-23 09:13:13 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nil(t, s.Start())
|
2020-06-23 09:13:13 +00:00
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
|
|
|
|
|
req := createTestMessageWithType("1.0.0.127.in-addr.arpa.", dns.TypePTR)
|
2020-06-23 09:13:13 +00:00
|
|
|
|
|
|
|
|
|
resp, err := dns.Exchange(req, addr.String())
|
2021-02-02 12:13:12 +00:00
|
|
|
|
|
2020-06-23 09:13:13 +00:00
|
|
|
|
assert.Nil(t, err)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Len(t, resp.Answer, 1)
|
2020-06-23 09:13:13 +00:00
|
|
|
|
assert.Equal(t, dns.TypePTR, resp.Answer[0].Header().Rrtype)
|
|
|
|
|
assert.Equal(t, "1.0.0.127.in-addr.arpa.", resp.Answer[0].Header().Name)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
|
2020-06-23 09:13:13 +00:00
|
|
|
|
ptr := resp.Answer[0].(*dns.PTR)
|
|
|
|
|
assert.Equal(t, "localhost.", ptr.Ptr)
|
|
|
|
|
|
|
|
|
|
s.Close()
|
|
|
|
|
}
|
2020-09-11 08:53:36 +00:00
|
|
|
|
|
|
|
|
|
func TestPTRResponseFromHosts(t *testing.T) {
|
|
|
|
|
c := dnsfilter.Config{
|
|
|
|
|
AutoHosts: &util.AutoHosts{},
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Prepare test hosts file.
|
|
|
|
|
hf, err := ioutil.TempFile("", "")
|
|
|
|
|
if assert.Nil(t, err) {
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
assert.Nil(t, hf.Close())
|
|
|
|
|
assert.Nil(t, os.Remove(hf.Name()))
|
|
|
|
|
})
|
|
|
|
|
}
|
2020-09-11 08:53:36 +00:00
|
|
|
|
|
|
|
|
|
_, _ = hf.WriteString(" 127.0.0.1 host # comment \n")
|
|
|
|
|
_, _ = hf.WriteString(" ::1 localhost#comment \n")
|
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
// Init auto hosts.
|
2020-09-11 08:53:36 +00:00
|
|
|
|
c.AutoHosts.Init(hf.Name())
|
2021-02-02 12:13:12 +00:00
|
|
|
|
t.Cleanup(c.AutoHosts.Close)
|
2020-09-11 08:53:36 +00:00
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
|
s := NewServer(DNSCreateParams{DNSFilter: dnsfilter.New(&c, nil)})
|
2020-09-11 08:53:36 +00:00
|
|
|
|
s.conf.UDPListenAddr = &net.UDPAddr{Port: 0}
|
|
|
|
|
s.conf.TCPListenAddr = &net.TCPAddr{Port: 0}
|
|
|
|
|
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
|
|
|
|
|
s.conf.FilteringConfig.ProtectionEnabled = true
|
2021-02-02 12:13:12 +00:00
|
|
|
|
assert.Nil(t, s.Prepare(nil))
|
|
|
|
|
|
2020-09-11 08:53:36 +00:00
|
|
|
|
assert.Nil(t, s.Start())
|
|
|
|
|
|
|
|
|
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
req := createTestMessageWithType("1.0.0.127.in-addr.arpa.", dns.TypePTR)
|
2020-09-11 08:53:36 +00:00
|
|
|
|
|
|
|
|
|
resp, err := dns.Exchange(req, addr.String())
|
|
|
|
|
assert.Nil(t, err)
|
2021-01-13 13:56:05 +00:00
|
|
|
|
assert.Len(t, resp.Answer, 1)
|
2020-09-11 08:53:36 +00:00
|
|
|
|
assert.Equal(t, dns.TypePTR, resp.Answer[0].Header().Rrtype)
|
|
|
|
|
assert.Equal(t, "1.0.0.127.in-addr.arpa.", resp.Answer[0].Header().Name)
|
2021-02-02 12:13:12 +00:00
|
|
|
|
|
2020-09-11 08:53:36 +00:00
|
|
|
|
ptr := resp.Answer[0].(*dns.PTR)
|
|
|
|
|
assert.Equal(t, "host.", ptr.Ptr)
|
|
|
|
|
|
|
|
|
|
s.Close()
|
|
|
|
|
}
|