Pull request: 6122-dnsforward: ipv6 hints filtering

Merge in DNS/adguard-home from 6122-ipv6hints-filtering to master

Squashed commit of the following:

commit 4c0923de9110ebd5dac28dbfbffeb7f834d7c567
Merge: b1ba1a9a8 4b4036fa6
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 22 17:00:46 2023 +0300

    Merge remote-tracking branch 'origin/master' into 6122-ipv6hints-filtering

commit b1ba1a9a8641ae846d0360bd50115153ff7c3b19
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 22 15:56:45 2023 +0300

    client: disable ipv6

commit 34f2a19aaec0928e83469945d807d9339715d671
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 22 15:16:27 2023 +0300

    client: disable ipv6

commit e0387597f81163c9e76bcf20307099c1ca72ca22
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 22 15:11:45 2023 +0300

    dnsforward: imp code

commit 22cdac4516759edbc6a81dd7636f0170fa669071
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 22 13:59:22 2023 +0300

    dnsforward: ipv6 hints filtering
This commit is contained in:
Dimitry Kolyshev 2023-08-22 17:18:35 +03:00
parent 4b4036fa6a
commit cb6d4620c5
4 changed files with 114 additions and 6 deletions

View file

@ -25,6 +25,8 @@ NOTE: Add new changes BELOW THIS COMMENT.
### Added
- IPv6 hints are now filtered in case IPv6 addresses resolving is disabled
([#6122]).
- The ability to set fallback DNS servers in the configuration file ([#3701]).
- While adding or updating blocklists, the title can now be parsed from
`! Title:` definition of the blocklist's source ([#6020]).
@ -76,6 +78,7 @@ In this release, the schema version has changed from 24 to 25.
[#6020]: https://github.com/AdguardTeam/AdGuardHome/issues/6020
[#6053]: https://github.com/AdguardTeam/AdGuardHome/issues/6053
[#6093]: https://github.com/AdguardTeam/AdGuardHome/issues/6093
[#6122]: https://github.com/AdguardTeam/AdGuardHome/issues/6122
<!--
NOTE: Add new changes ABOVE THIS COMMENT.

View file

@ -568,7 +568,7 @@
"rewrite_A": "<0>A</0>: special value, keep <0>A</0> records from the upstream",
"rewrite_AAAA": "<0>AAAA</0>: special value, keep <0>AAAA</0> records from the upstream",
"disable_ipv6": "Disable resolving of IPv6 addresses",
"disable_ipv6_desc": "Drop all DNS queries for IPv6 addresses (type AAAA).",
"disable_ipv6_desc": "Drop all DNS queries for IPv6 addresses (type AAAA) and remove IPv6 hints from HTTPS responses.",
"fastest_addr": "Fastest IP address",
"fastest_addr_desc": "Query all DNS servers and return the fastest IP address among all responses. This slows down DNS queries as AdGuard Home has to wait for responses from all DNS servers, but improves the overall connectivity.",
"autofix_warning_text": "If you click \"Fix\", AdGuard Home will configure your system to use AdGuard Home DNS server.",

View file

@ -12,6 +12,7 @@ import (
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
"golang.org/x/exp/slices"
)
// beforeRequestHandler is the handler that is called before any other
@ -208,12 +209,23 @@ func (s *Server) filterDNSResponse(
return nil, nil
}
// removeIPv6Hints deletes IPv6 hints from RR values.
func removeIPv6Hints(rr *dns.HTTPS) {
rr.Value = slices.DeleteFunc(rr.Value, func(kv dns.SVCBKeyValue) (del bool) {
_, ok := kv.(*dns.SVCBIPv6Hint)
return ok
})
}
// filterHTTPSRecords filters HTTPS answers information through all rule list
// filters of the server filters.
func (s *Server) filterHTTPSRecords(
rr *dns.HTTPS,
setts *filtering.Settings,
) (r *filtering.Result, err error) {
// filters of the server filters. Removes IPv6 hints if IPv6 resolving is
// disabled.
func (s *Server) filterHTTPSRecords(rr *dns.HTTPS, setts *filtering.Settings) (r *filtering.Result, err error) {
if s.conf.AAAADisabled {
removeIPv6Hints(rr)
}
for _, kv := range rr.Value {
var ips []net.IP
switch hint := kv.(type) {

View file

@ -113,6 +113,99 @@ func TestServer_ProcessInitial(t *testing.T) {
}
}
func TestServer_ProcessFilteringAfterResponse(t *testing.T) {
t.Parallel()
var (
testIPv4 net.IP = netip.MustParseAddr("1.1.1.1").AsSlice()
testIPv6 net.IP = netip.MustParseAddr("1234::cdef").AsSlice()
)
testCases := []struct {
name string
req *dns.Msg
aaaaDisabled bool
respAns []dns.RR
wantRC resultCode
wantRespAns []dns.RR
}{{
name: "pass",
req: createTestMessageWithType(aghtest.ReqFQDN, dns.TypeHTTPS),
aaaaDisabled: false,
respAns: newSVCBHintsAnswer(
aghtest.ReqFQDN,
[]dns.SVCBKeyValue{
&dns.SVCBIPv4Hint{Hint: []net.IP{testIPv4}},
&dns.SVCBIPv6Hint{Hint: []net.IP{testIPv6}},
},
),
wantRespAns: newSVCBHintsAnswer(
aghtest.ReqFQDN,
[]dns.SVCBKeyValue{
&dns.SVCBIPv4Hint{Hint: []net.IP{testIPv4}},
&dns.SVCBIPv6Hint{Hint: []net.IP{testIPv6}},
},
),
wantRC: resultCodeSuccess,
}, {
name: "filter",
req: createTestMessageWithType(aghtest.ReqFQDN, dns.TypeHTTPS),
aaaaDisabled: true,
respAns: newSVCBHintsAnswer(
aghtest.ReqFQDN,
[]dns.SVCBKeyValue{
&dns.SVCBIPv4Hint{Hint: []net.IP{testIPv4}},
&dns.SVCBIPv6Hint{Hint: []net.IP{testIPv6}},
},
),
wantRespAns: newSVCBHintsAnswer(
aghtest.ReqFQDN,
[]dns.SVCBKeyValue{
&dns.SVCBIPv4Hint{Hint: []net.IP{testIPv4}},
},
),
wantRC: resultCodeSuccess,
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
c := ServerConfig{
FilteringConfig: FilteringConfig{
AAAADisabled: tc.aaaaDisabled,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
},
}
s := createTestServer(t, &filtering.Config{}, c, nil)
resp := newResp(dns.RcodeSuccess, tc.req, tc.respAns)
dctx := &dnsContext{
setts: &filtering.Settings{
FilteringEnabled: true,
ProtectionEnabled: true,
},
protectionEnabled: true,
responseFromUpstream: true,
result: &filtering.Result{},
proxyCtx: &proxy.DNSContext{
Proto: proxy.ProtoUDP,
Req: tc.req,
Res: resp,
Addr: testClientAddr,
},
}
gotRC := s.processFilteringAfterResponse(dctx)
assert.Equal(t, tc.wantRC, gotRC)
assert.Equal(t, newResp(dns.RcodeSuccess, tc.req, tc.wantRespAns), dctx.proxyCtx.Res)
})
}
}
func TestServer_ProcessDDRQuery(t *testing.T) {
dohSVCB := &dns.SVCB{
Priority: 1,