From 0cff3dbcda254b1354aac9354012385e59af66f0 Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Wed, 24 Apr 2024 16:22:50 +0300 Subject: [PATCH] Pull request: AG-31863-dnsforward-tests Merge in DNS/adguard-home from AG-31863-dnsforward-tests to master Squashed commit of the following: commit cbdad627c00b30a17af843d98236fe9758b7ddee Author: Dimitry Kolyshev Date: Wed Apr 24 15:00:15 2024 +0200 dnsforward: imp tests commit b71304a925c0ea49440e493dc65accadc6e47c5f Author: Dimitry Kolyshev Date: Wed Apr 24 12:53:51 2024 +0200 dnsforward: imp tests commit 3c42fcaa4906fce48b179a1c523e33839b2a8eee Merge: 50888df66 60f48e2d0 Author: Dimitry Kolyshev Date: Wed Apr 24 08:41:19 2024 +0200 Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests commit 50888df6616085872d956c42898ab0eff6c5f5d4 Author: Dimitry Kolyshev Date: Wed Apr 24 08:39:37 2024 +0200 dnsforward: imp code commit dcd5e41f13d698ce7a6beb0a601910ae03ff4407 Merge: af2507b2a f85d04831 Author: Dimitry Kolyshev Date: Tue Apr 23 10:02:45 2024 +0200 Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests commit af2507b2ace94d0c39803c2d21273cf11a00843e Author: Dimitry Kolyshev Date: Tue Apr 23 10:01:30 2024 +0200 dnsforward: imp tests commit 67fc9d3d9c6210e600ca3b26abf7ebfffca5e770 Author: Dimitry Kolyshev Date: Mon Apr 22 10:37:45 2024 +0200 dnsforward: imp tests commit e7f7df2b688be525ee7582a4e161a4837124e74b Merge: c610a6c88 762ef4a6d Author: Dimitry Kolyshev Date: Mon Apr 22 09:51:04 2024 +0200 Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests commit c610a6c886554f6a2677c993c1c7aae4ca99228e Author: Dimitry Kolyshev Date: Fri Apr 19 12:28:49 2024 +0200 dnsforward: imp tests commit ca252e8fa28b70f303068775cc682682dd41e77c Author: Dimitry Kolyshev Date: Fri Apr 19 11:58:49 2024 +0200 dnsforward: imp tests commit 9d4de18934b1c5b0ae2edbec98bc84d5e0b23126 Author: Dimitry Kolyshev Date: Fri Apr 19 11:38:15 2024 +0200 dnsforward: imp tests commit a349374d90f48724ddca637e3d547f90026ff72a Merge: 2243770b3 48c6242a7 Author: Dimitry Kolyshev Date: Wed Apr 17 11:02:56 2024 +0200 Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests commit 2243770b3a54a55eaf4fd48328a8e40a7b8a8349 Author: Dimitry Kolyshev Date: Tue Apr 16 10:56:40 2024 +0200 dnsforward: imp tests commit 4c4b565eec0ce8839b94cbaa0b29be6355e3c2e4 Merge: f1e4b72a8 201ac73cf Author: Dimitry Kolyshev Date: Tue Apr 16 10:53:48 2024 +0200 Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests commit f1e4b72a8aa4fd0bbc738d959ca9be2f19fbc338 Author: Dimitry Kolyshev Date: Mon Apr 15 12:36:21 2024 +0200 dnsforward: imp tests commit 6ee6cc9519ddd31f0e78c7521ec612404f85e4b5 Author: Dimitry Kolyshev Date: Sun Apr 14 13:55:09 2024 +0200 dnsforward: add test --- internal/dnsforward/beforerequest.go | 2 +- .../dnsforward/beforerequest_internal_test.go | 299 ++++++++++++++++++ 2 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 internal/dnsforward/beforerequest_internal_test.go diff --git a/internal/dnsforward/beforerequest.go b/internal/dnsforward/beforerequest.go index 21bc43a3..8a1b0272 100644 --- a/internal/dnsforward/beforerequest.go +++ b/internal/dnsforward/beforerequest.go @@ -18,7 +18,7 @@ var _ proxy.BeforeRequestHandler = (*Server)(nil) // including logs. It performs access checks and puts the client ID, if there // is one, into the server's cache. // -// TODO(e.burkov): Write tests. +// TODO(d.kolyshev): Extract to separate package. func (s *Server) HandleBefore( _ *proxy.Proxy, pctx *proxy.DNSContext, diff --git a/internal/dnsforward/beforerequest_internal_test.go b/internal/dnsforward/beforerequest_internal_test.go new file mode 100644 index 00000000..7e0d6e9b --- /dev/null +++ b/internal/dnsforward/beforerequest_internal_test.go @@ -0,0 +1,299 @@ +package dnsforward + +import ( + "crypto/tls" + "net" + "testing" + "time" + + "github.com/AdguardTeam/AdGuardHome/internal/aghtest" + "github.com/AdguardTeam/AdGuardHome/internal/filtering" + "github.com/AdguardTeam/dnsproxy/proxy" + "github.com/miekg/dns" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + blockedHost = "blockedhost.org" + testFQDN = "example.org." + dnsClientTimeout = 200 * time.Millisecond +) + +func TestServer_HandleBefore_tls(t *testing.T) { + t.Parallel() + + const clientID = "client-1" + + testCases := []struct { + clientSrvName string + name string + host string + allowedClients []string + disallowedClients []string + blockedHosts []string + wantRCode int + }{{ + clientSrvName: tlsServerName, + name: "allow_all", + host: testFQDN, + allowedClients: []string{}, + disallowedClients: []string{}, + blockedHosts: []string{}, + wantRCode: dns.RcodeSuccess, + }, { + clientSrvName: "%" + "." + tlsServerName, + name: "invalid_client_id", + host: testFQDN, + allowedClients: []string{}, + disallowedClients: []string{}, + blockedHosts: []string{}, + wantRCode: dns.RcodeServerFailure, + }, { + clientSrvName: clientID + "." + tlsServerName, + name: "allowed_client_allowed", + host: testFQDN, + allowedClients: []string{clientID}, + disallowedClients: []string{}, + blockedHosts: []string{}, + wantRCode: dns.RcodeSuccess, + }, { + clientSrvName: "client-2." + tlsServerName, + name: "allowed_client_rejected", + host: testFQDN, + allowedClients: []string{clientID}, + disallowedClients: []string{}, + blockedHosts: []string{}, + wantRCode: dns.RcodeRefused, + }, { + clientSrvName: tlsServerName, + name: "disallowed_client_allowed", + host: testFQDN, + allowedClients: []string{}, + disallowedClients: []string{clientID}, + blockedHosts: []string{}, + wantRCode: dns.RcodeSuccess, + }, { + clientSrvName: clientID + "." + tlsServerName, + name: "disallowed_client_rejected", + host: testFQDN, + allowedClients: []string{}, + disallowedClients: []string{clientID}, + blockedHosts: []string{}, + wantRCode: dns.RcodeRefused, + }, { + clientSrvName: tlsServerName, + name: "blocked_hosts_allowed", + host: testFQDN, + allowedClients: []string{}, + disallowedClients: []string{}, + blockedHosts: []string{blockedHost}, + wantRCode: dns.RcodeSuccess, + }, { + clientSrvName: tlsServerName, + name: "blocked_hosts_rejected", + host: dns.Fqdn(blockedHost), + allowedClients: []string{}, + disallowedClients: []string{}, + blockedHosts: []string{blockedHost}, + wantRCode: dns.RcodeRefused, + }} + + localAns := []dns.RR{&dns.A{ + Hdr: dns.RR_Header{ + Name: testFQDN, + Rrtype: dns.TypeA, + Class: dns.ClassINET, + Ttl: 3600, + Rdlength: 4, + }, + A: net.IP{1, 2, 3, 4}, + }} + localUpsHdlr := dns.HandlerFunc(func(w dns.ResponseWriter, req *dns.Msg) { + resp := (&dns.Msg{}).SetReply(req) + resp.Answer = localAns + + require.NoError(t, w.WriteMsg(resp)) + }) + localUpsAddr := aghtest.StartLocalhostUpstream(t, localUpsHdlr).String() + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + s, _ := createTestTLS(t, TLSConfig{ + TLSListenAddrs: []*net.TCPAddr{{}}, + ServerName: tlsServerName, + }) + + s.conf.UpstreamDNS = []string{localUpsAddr} + + s.conf.AllowedClients = tc.allowedClients + s.conf.DisallowedClients = tc.disallowedClients + s.conf.BlockedHosts = tc.blockedHosts + + err := s.Prepare(&s.conf) + require.NoError(t, err) + + startDeferStop(t, s) + + tlsConfig := &tls.Config{ + InsecureSkipVerify: true, + ServerName: tc.clientSrvName, + } + + client := &dns.Client{ + Net: "tcp-tls", + TLSConfig: tlsConfig, + Timeout: dnsClientTimeout, + } + + req := createTestMessage(tc.host) + addr := s.dnsProxy.Addr(proxy.ProtoTLS).String() + + reply, _, err := client.Exchange(req, addr) + require.NoError(t, err) + + assert.Equal(t, tc.wantRCode, reply.Rcode) + if tc.wantRCode == dns.RcodeSuccess { + assert.Equal(t, localAns, reply.Answer) + } else { + assert.Empty(t, reply.Answer) + } + }) + } +} + +func TestServer_HandleBefore_udp(t *testing.T) { + t.Parallel() + + const ( + clientIPv4 = "127.0.0.1" + clientIPv6 = "::1" + ) + + clientIPs := []string{clientIPv4, clientIPv6} + + testCases := []struct { + name string + host string + allowedClients []string + disallowedClients []string + blockedHosts []string + wantTimeout bool + }{{ + name: "allow_all", + host: testFQDN, + allowedClients: []string{}, + disallowedClients: []string{}, + blockedHosts: []string{}, + wantTimeout: false, + }, { + name: "allowed_client_allowed", + host: testFQDN, + allowedClients: clientIPs, + disallowedClients: []string{}, + blockedHosts: []string{}, + wantTimeout: false, + }, { + name: "allowed_client_rejected", + host: testFQDN, + allowedClients: []string{"1:2:3::4"}, + disallowedClients: []string{}, + blockedHosts: []string{}, + wantTimeout: true, + }, { + name: "disallowed_client_allowed", + host: testFQDN, + allowedClients: []string{}, + disallowedClients: []string{"1:2:3::4"}, + blockedHosts: []string{}, + wantTimeout: false, + }, { + name: "disallowed_client_rejected", + host: testFQDN, + allowedClients: []string{}, + disallowedClients: clientIPs, + blockedHosts: []string{}, + wantTimeout: true, + }, { + name: "blocked_hosts_allowed", + host: testFQDN, + allowedClients: []string{}, + disallowedClients: []string{}, + blockedHosts: []string{blockedHost}, + wantTimeout: false, + }, { + name: "blocked_hosts_rejected", + host: dns.Fqdn(blockedHost), + allowedClients: []string{}, + disallowedClients: []string{}, + blockedHosts: []string{blockedHost}, + wantTimeout: true, + }} + + localAns := []dns.RR{&dns.A{ + Hdr: dns.RR_Header{ + Name: testFQDN, + Rrtype: dns.TypeA, + Class: dns.ClassINET, + Ttl: 3600, + Rdlength: 4, + }, + A: net.IP{1, 2, 3, 4}, + }} + localUpsHdlr := dns.HandlerFunc(func(w dns.ResponseWriter, req *dns.Msg) { + resp := (&dns.Msg{}).SetReply(req) + resp.Answer = localAns + + require.NoError(t, w.WriteMsg(resp)) + }) + localUpsAddr := aghtest.StartLocalhostUpstream(t, localUpsHdlr).String() + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + s := createTestServer(t, &filtering.Config{ + BlockingMode: filtering.BlockingModeDefault, + }, ServerConfig{ + UDPListenAddrs: []*net.UDPAddr{{}}, + TCPListenAddrs: []*net.TCPAddr{{}}, + Config: Config{ + AllowedClients: tc.allowedClients, + DisallowedClients: tc.disallowedClients, + BlockedHosts: tc.blockedHosts, + UpstreamDNS: []string{localUpsAddr}, + UpstreamMode: UpstreamModeLoadBalance, + EDNSClientSubnet: &EDNSClientSubnet{Enabled: false}, + }, + ServePlainDNS: true, + }) + + startDeferStop(t, s) + + client := &dns.Client{ + Net: "udp", + Timeout: dnsClientTimeout, + } + + req := createTestMessage(tc.host) + addr := s.dnsProxy.Addr(proxy.ProtoUDP).String() + + reply, _, err := client.Exchange(req, addr) + if tc.wantTimeout { + wantErr := &net.OpError{} + require.ErrorAs(t, err, &wantErr) + assert.True(t, wantErr.Timeout()) + + assert.Nil(t, reply) + } else { + require.NoError(t, err) + require.NotNil(t, reply) + + assert.Equal(t, dns.RcodeSuccess, reply.Rcode) + assert.Equal(t, localAns, reply.Answer) + } + }) + } +}