Pull request 1744: 1472-edns-custom-ip

Merge in DNS/adguard-home from 1472-edns-custom-ip to master

Updates #1472.

Squashed commit of the following:

commit 07460c3adf7747fd9ec1b4a3d04fb459dec44280
Merge: 65455430 ae653f16
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Mar 1 15:38:46 2023 +0300

    Merge branch 'master' into 1472-edns-custom-ip

commit 65455430993e4a62c49e1f45def909b0a135af3b
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Mar 1 15:37:17 2023 +0300

    dnsforward: add todo

commit e1978ad4b6051f29185ef32973d20bc70f2a6634
Merge: 6cd98f42 bb226434
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Mar 1 11:32:23 2023 +0300

    Merge branch 'master' into 1472-edns-custom-ip

commit 6cd98f4235b1b52d443c1950f2516af3cc4fb258
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Mar 1 11:31:16 2023 +0300

    all: fix chlog; fix field alignment

commit defdec623919c23ab446324828d08839469669e1
Merge: 1130ebd5 a772212d
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Feb 28 12:17:23 2023 +0300

    Merge branch 'master' into 1472-edns-custom-ip

commit 1130ebd509bf4f7ec25fbb53717576e273dbfff2
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Feb 28 12:13:30 2023 +0300

    all: add use_custom field

commit ec0cdc7af0f96f761ed85516bbcae2567fd6f7d2
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Feb 27 13:59:13 2023 +0300

    all: fix chlog; imp code

commit f8450cfcd6054f32d6ea0a5e26c551fe153a0b21
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Feb 27 11:28:16 2023 +0300

    dnsforward: fix fmt

commit 54a344e5bb17aae7ca213ed66b85f06ef6585316
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Feb 27 11:11:52 2023 +0300

    all: fix chlog; add test case

commit 47b5476f6621c6ea31aa496d4113445a8e8bceb4
Merge: 8724f374 304f2ba2
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Feb 22 16:33:07 2023 +0300

    Merge branch 'master' into 1472-edns-custom-ip

commit 8724f3745ccc29849a4001f79b055c7ebeb19106
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Feb 22 16:31:40 2023 +0300

    all: fix comments

commit d2b1528ba333e7669795a3fb80355ff7d90cf4f5
Merge: 7898c23a 76a513cd
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Feb 22 11:53:25 2023 +0300

    Merge branch 'master' into 1472-edns-custom-ip

commit 7898c23ab991bc516bcc2f41e47bed15582fd962
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Feb 22 11:52:37 2023 +0300

    all: upd chlog

commit 8763261dcb4187a93104955e7cb440965e2b6739
Merge: d28394b3 ff9b24ad
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Feb 21 17:12:03 2023 +0300

    Merge branch 'master' into 1472-edns-custom-ip

commit d28394b3c980b10f28c6c38ce35f368edb11d314
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Feb 21 17:11:29 2023 +0300

    home: fix default value

commit 1a5da3f267706baa83eebe1923ea1b0b4e79fd6c
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Feb 21 13:37:04 2023 +0300

    all: add custom ip for edns
This commit is contained in:
Stanislav Chzhen 2023-03-01 16:16:16 +03:00
parent ae653f166f
commit 012e5beb51
10 changed files with 333 additions and 46 deletions

View file

@ -25,9 +25,43 @@ NOTE: Add new changes BELOW THIS COMMENT.
### Added ### Added
- The ability to set custom IP for EDNS Client Subnet by using the new
`dns.edns_client_subnet.use_custom` and `dns.edns_client_subnet.custom_ip`
fields ([#1472]). The UI changes are coming in the upcoming releases.
- The ability to use `dnstype` rules in the disallowed domains list ([#5468]). - The ability to use `dnstype` rules in the disallowed domains list ([#5468]).
This allows dropping requests based on their question types. This allows dropping requests based on their question types.
### Changed
#### Configuration Changes
In this release, the schema version has changed from 16 to 17.
- Property `edns_client_subnet`, which in schema versions 16 and earlier used
to be a part of the `dns` object, is now part of the `dns.edns_client_subnet`
object:
```yaml
# BEFORE:
'dns':
# …
'edns_client_subnet': false
# AFTER:
'dns':
# …
'edns_client_subnet':
'enabled': false
'use_custom': false
'custom_ip': ''
```
To rollback this change, move the value of `dns.edns_client_subnet.enabled`
into the `dns.edns_client_subnet`, remove the fields
`dns.edns_client_subnet.enabled`, `dns.edns_client_subnet.use_custom`,
`dns.edns_client_subnet.custom_ip`, and change the `schema_version` back to
`16`.
### Fixed ### Fixed
- Various dark theme bugs ([#5439], [#5441], [#5442], [#5515]). - Various dark theme bugs ([#5439], [#5441], [#5442], [#5515]).
@ -37,6 +71,7 @@ NOTE: Add new changes BELOW THIS COMMENT.
been relaxed to meet those from [RFC 3696][rfc3696] ([#4884]). been relaxed to meet those from [RFC 3696][rfc3696] ([#4884]).
- Failing service installation via script on FreeBSD ([#5431]). - Failing service installation via script on FreeBSD ([#5431]).
[#1472]: https://github.com/AdguardTeam/AdGuardHome/issues/1472
[#4884]: https://github.com/AdguardTeam/AdGuardHome/issues/4884 [#4884]: https://github.com/AdguardTeam/AdGuardHome/issues/4884
[#5270]: https://github.com/AdguardTeam/AdGuardHome/issues/5270 [#5270]: https://github.com/AdguardTeam/AdGuardHome/issues/5270
[#5373]: https://github.com/AdguardTeam/AdGuardHome/issues/5373 [#5373]: https://github.com/AdguardTeam/AdGuardHome/issues/5373
@ -129,6 +164,7 @@ In this release, the schema version has changed from 14 to 16.
'file_enabled': true 'file_enabled': true
'interval': '2160h' 'interval': '2160h'
'size_memory': 1000 'size_memory': 1000
'ignored': []
``` ```
To rollback this change, rename and move properties back into the `dns` To rollback this change, rename and move properties back into the `dns`

View file

@ -53,7 +53,6 @@ const (
// The zero FilteringConfig is empty and ready for use. // The zero FilteringConfig is empty and ready for use.
type FilteringConfig struct { type FilteringConfig struct {
// Callbacks for other modules // Callbacks for other modules
// --
// FilterHandler is an optional additional filtering callback. // FilterHandler is an optional additional filtering callback.
FilterHandler func(clientAddr net.IP, clientID string, settings *filtering.Settings) `yaml:"-"` FilterHandler func(clientAddr net.IP, clientID string, settings *filtering.Settings) `yaml:"-"`
@ -64,50 +63,82 @@ type FilteringConfig struct {
GetCustomUpstreamByClient func(id string) (conf *proxy.UpstreamConfig, err error) `yaml:"-"` GetCustomUpstreamByClient func(id string) (conf *proxy.UpstreamConfig, err error) `yaml:"-"`
// Protection configuration // Protection configuration
// --
ProtectionEnabled bool `yaml:"protection_enabled"` // whether or not use any of filtering features // ProtectionEnabled defines whether or not use any of filtering features.
BlockingMode BlockingMode `yaml:"blocking_mode"` // mode how to answer filtered requests ProtectionEnabled bool `yaml:"protection_enabled"`
BlockingIPv4 net.IP `yaml:"blocking_ipv4"` // IP address to be returned for a blocked A request
BlockingIPv6 net.IP `yaml:"blocking_ipv6"` // IP address to be returned for a blocked AAAA request
BlockedResponseTTL uint32 `yaml:"blocked_response_ttl"` // if 0, then default is used (3600)
// IP (or domain name) which is used to respond to DNS requests blocked by parental control or safe-browsing // BlockingMode defines the way how blocked responses are constructed.
ParentalBlockHost string `yaml:"parental_block_host"` BlockingMode BlockingMode `yaml:"blocking_mode"`
// BlockingIPv4 is the IP address to be returned for a blocked A request.
BlockingIPv4 net.IP `yaml:"blocking_ipv4"`
// BlockingIPv6 is the IP address to be returned for a blocked AAAA
// request.
BlockingIPv6 net.IP `yaml:"blocking_ipv6"`
// BlockedResponseTTL is the time-to-live value for blocked responses. If
// 0, then default value is used (3600).
BlockedResponseTTL uint32 `yaml:"blocked_response_ttl"`
// ParentalBlockHost is the IP (or domain name) which is used to respond to
// DNS requests blocked by parental control.
ParentalBlockHost string `yaml:"parental_block_host"`
// SafeBrowsingBlockHost is the IP (or domain name) which is used to
// respond to DNS requests blocked by safe-browsing.
SafeBrowsingBlockHost string `yaml:"safebrowsing_block_host"` SafeBrowsingBlockHost string `yaml:"safebrowsing_block_host"`
// Anti-DNS amplification // Anti-DNS amplification
// --
Ratelimit uint32 `yaml:"ratelimit"` // max number of requests per second from a given IP (0 to disable) // Ratelimit is the maximum number of requests per second from a given IP
RatelimitWhitelist []string `yaml:"ratelimit_whitelist"` // a list of whitelisted client IP addresses // (0 to disable).
RefuseAny bool `yaml:"refuse_any"` // if true, refuse ANY requests Ratelimit uint32 `yaml:"ratelimit"`
// RatelimitWhitelist is the list of whitelisted client IP addresses.
RatelimitWhitelist []string `yaml:"ratelimit_whitelist"`
// RefuseAny, if true, refuse ANY requests.
RefuseAny bool `yaml:"refuse_any"`
// Upstream DNS servers configuration // Upstream DNS servers configuration
// --
UpstreamDNS []string `yaml:"upstream_dns"` // UpstreamDNS is the list of upstream DNS servers.
UpstreamDNSFileName string `yaml:"upstream_dns_file"` UpstreamDNS []string `yaml:"upstream_dns"`
BootstrapDNS []string `yaml:"bootstrap_dns"` // a list of bootstrap DNS for DoH and DoT (plain DNS only)
AllServers bool `yaml:"all_servers"` // if true, parallel queries to all configured upstream servers are enabled // UpstreamDNSFileName, if set, points to the file which contains upstream
FastestAddr bool `yaml:"fastest_addr"` // use Fastest Address algorithm // DNS servers.
UpstreamDNSFileName string `yaml:"upstream_dns_file"`
// BootstrapDNS is the list of bootstrap DNS servers for DoH and DoT
// resolvers (plain DNS only).
BootstrapDNS []string `yaml:"bootstrap_dns"`
// AllServers, if true, parallel queries to all configured upstream servers
// are enabled.
AllServers bool `yaml:"all_servers"`
// FastestAddr, if true, use Fastest Address algorithm.
FastestAddr bool `yaml:"fastest_addr"`
// FastestTimeout replaces the default timeout for dialing IP addresses // FastestTimeout replaces the default timeout for dialing IP addresses
// when FastestAddr is true. // when FastestAddr is true.
FastestTimeout timeutil.Duration `yaml:"fastest_timeout"` FastestTimeout timeutil.Duration `yaml:"fastest_timeout"`
// Access settings // Access settings
// --
// AllowedClients is the slice of IP addresses, CIDR networks, and ClientIDs // AllowedClients is the slice of IP addresses, CIDR networks, and
// of allowed clients. If not empty, only these clients are allowed, and // ClientIDs of allowed clients. If not empty, only these clients are
// [FilteringConfig.DisallowedClients] are ignored. // allowed, and [FilteringConfig.DisallowedClients] are ignored.
AllowedClients []string `yaml:"allowed_clients"` AllowedClients []string `yaml:"allowed_clients"`
// DisallowedClients is the slice of IP addresses, CIDR networks, and // DisallowedClients is the slice of IP addresses, CIDR networks, and
// ClientIDs of disallowed clients. // ClientIDs of disallowed clients.
DisallowedClients []string `yaml:"disallowed_clients"` DisallowedClients []string `yaml:"disallowed_clients"`
BlockedHosts []string `yaml:"blocked_hosts"` // hosts that should be blocked // BlockedHosts is the list of hosts that should be blocked.
BlockedHosts []string `yaml:"blocked_hosts"`
// TrustedProxies is the list of IP addresses and CIDR networks to detect // TrustedProxies is the list of IP addresses and CIDR networks to detect
// proxy servers addresses the DoH requests from which should be handled. // proxy servers addresses the DoH requests from which should be handled.
// The value of nil or an empty slice for this field makes Proxy not trust // The value of nil or an empty slice for this field makes Proxy not trust
@ -115,26 +146,46 @@ type FilteringConfig struct {
TrustedProxies []string `yaml:"trusted_proxies"` TrustedProxies []string `yaml:"trusted_proxies"`
// DNS cache settings // DNS cache settings
// --
CacheSize uint32 `yaml:"cache_size"` // DNS cache size (in bytes) // CacheSize is the DNS cache size (in bytes).
CacheMinTTL uint32 `yaml:"cache_ttl_min"` // override TTL value (minimum) received from upstream server CacheSize uint32 `yaml:"cache_size"`
CacheMaxTTL uint32 `yaml:"cache_ttl_max"` // override TTL value (maximum) received from upstream server
// CacheMinTTL is the override TTL value (minimum) received from upstream
// server.
CacheMinTTL uint32 `yaml:"cache_ttl_min"`
// CacheMaxTTL is the override TTL value (maximum) received from upstream
// server.
CacheMaxTTL uint32 `yaml:"cache_ttl_max"`
// CacheOptimistic defines if optimistic cache mechanism should be used. // CacheOptimistic defines if optimistic cache mechanism should be used.
CacheOptimistic bool `yaml:"cache_optimistic"` CacheOptimistic bool `yaml:"cache_optimistic"`
// Other settings // Other settings
// --
BogusNXDomain []string `yaml:"bogus_nxdomain"` // transform responses with these IP addresses to NXDOMAIN // BogusNXDomain is the list of IP addresses, responses with them will be
AAAADisabled bool `yaml:"aaaa_disabled"` // Respond with an empty answer to all AAAA requests // transformed to NXDOMAIN.
EnableDNSSEC bool `yaml:"enable_dnssec"` // Set AD flag in outcoming DNS request BogusNXDomain []string `yaml:"bogus_nxdomain"`
EnableEDNSClientSubnet bool `yaml:"edns_client_subnet"` // Enable EDNS Client Subnet option
MaxGoroutines uint32 `yaml:"max_goroutines"` // Max. number of parallel goroutines for processing incoming requests
HandleDDR bool `yaml:"handle_ddr"` // Handle DDR requests
// IpsetList is the ipset configuration that allows AdGuard Home to add // AAAADisabled, if true, respond with an empty answer to all AAAA
// IP addresses of the specified domain names to an ipset list. Syntax: // requests.
AAAADisabled bool `yaml:"aaaa_disabled"`
// EnableDNSSEC, if true, set AD flag in outcoming DNS request.
EnableDNSSEC bool `yaml:"enable_dnssec"`
// EDNSClientSubnet is the settings list for EDNS Client Subnet.
EDNSClientSubnet *EDNSClientSubnet `yaml:"edns_client_subnet"`
// MaxGoroutines is the max number of parallel goroutines for processing
// incoming requests.
MaxGoroutines uint32 `yaml:"max_goroutines"`
// HandleDDR, if true, handle DDR requests
HandleDDR bool `yaml:"handle_ddr"`
// IpsetList is the ipset configuration that allows AdGuard Home to add IP
// addresses of the specified domain names to an ipset list. Syntax:
// //
// DOMAIN[,DOMAIN].../IPSET_NAME // DOMAIN[,DOMAIN].../IPSET_NAME
// //
@ -146,6 +197,18 @@ type FilteringConfig struct {
IpsetListFileName string `yaml:"ipset_file"` IpsetListFileName string `yaml:"ipset_file"`
} }
// EDNSClientSubnet is the settings list for EDNS Client Subnet.
type EDNSClientSubnet struct {
// CustomIP for EDNS Client Subnet.
CustomIP string `yaml:"custom_ip"`
// Enabled defines if EDNS Client Subnet is enabled.
Enabled bool `yaml:"enabled"`
// UseCustom defines if CustomIP should be used.
UseCustom bool `yaml:"use_custom"`
}
// TLSConfig is the TLS configuration for HTTPS, DNS-over-HTTPS, and DNS-over-TLS // TLSConfig is the TLS configuration for HTTPS, DNS-over-HTTPS, and DNS-over-TLS
type TLSConfig struct { type TLSConfig struct {
cert tls.Certificate cert tls.Certificate
@ -270,12 +333,24 @@ func (s *Server) createProxyConfig() (conf proxy.Config, err error) {
UpstreamConfig: srvConf.UpstreamConfig, UpstreamConfig: srvConf.UpstreamConfig,
BeforeRequestHandler: s.beforeRequestHandler, BeforeRequestHandler: s.beforeRequestHandler,
RequestHandler: s.handleDNSRequest, RequestHandler: s.handleDNSRequest,
EnableEDNSClientSubnet: srvConf.EnableEDNSClientSubnet, EnableEDNSClientSubnet: srvConf.EDNSClientSubnet.Enabled,
MaxGoroutines: int(srvConf.MaxGoroutines), MaxGoroutines: int(srvConf.MaxGoroutines),
UseDNS64: srvConf.UseDNS64, UseDNS64: srvConf.UseDNS64,
DNS64Prefs: srvConf.DNS64Prefixes, DNS64Prefs: srvConf.DNS64Prefixes,
} }
if srvConf.EDNSClientSubnet.UseCustom {
// TODO(s.chzhen): Add wrapper around netip.Addr.
var ip net.IP
ip, err = netutil.ParseIP(srvConf.EDNSClientSubnet.CustomIP)
if err != nil {
return conf, fmt.Errorf("edns: %w", err)
}
// TODO(s.chzhen): Use netip.Addr instead of net.IP inside dnsproxy.
conf.EDNSAddr = ip
}
if srvConf.CacheSize != 0 { if srvConf.CacheSize != 0 {
conf.CacheEnabled = true conf.CacheEnabled = true
conf.CacheSizeBytes = int(srvConf.CacheSize) conf.CacheSizeBytes = int(srvConf.CacheSize)

View file

@ -287,6 +287,9 @@ func TestServer_HandleDNSRequest_dns64(t *testing.T) {
UDPListenAddrs: []*net.UDPAddr{{}}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
UseDNS64: true, UseDNS64: true,
FilteringConfig: FilteringConfig{
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
},
}, localUps) }, localUps)
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {

View file

@ -467,6 +467,11 @@ func TestServer_ProcessRestrictLocal(t *testing.T) {
s := createTestServer(t, &filtering.Config{}, ServerConfig{ s := createTestServer(t, &filtering.Config{}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
// TODO(s.chzhen): Add tests where EDNSClientSubnet.Enabled is true.
// Improve FilteringConfig declaration for tests.
FilteringConfig: FilteringConfig{
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
},
}, ups) }, ups)
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ups} s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ups}
startDeferStop(t, s) startDeferStop(t, s)
@ -539,6 +544,9 @@ func TestServer_ProcessLocalPTR_usingResolvers(t *testing.T) {
ServerConfig{ ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
},
}, },
aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) { aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
return aghalg.Coalesce( return aghalg.Coalesce(

View file

@ -156,6 +156,9 @@ func createTestTLS(t *testing.T, tlsConf TLSConfig) (s *Server, certPem []byte)
s = createTestServer(t, &filtering.Config{}, ServerConfig{ s = createTestServer(t, &filtering.Config{}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
},
}, nil) }, nil)
tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem
@ -267,6 +270,9 @@ func TestServer(t *testing.T) {
s := createTestServer(t, &filtering.Config{}, ServerConfig{ s := createTestServer(t, &filtering.Config{}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
},
}, nil) }, nil)
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()} s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
startDeferStop(t, s) startDeferStop(t, s)
@ -305,7 +311,8 @@ func TestServer_timeout(t *testing.T) {
srvConf := &ServerConfig{ srvConf := &ServerConfig{
UpstreamTimeout: timeout, UpstreamTimeout: timeout,
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
BlockingMode: BlockingModeDefault, BlockingMode: BlockingModeDefault,
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
}, },
} }
@ -323,6 +330,9 @@ func TestServer_timeout(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
s.conf.FilteringConfig.BlockingMode = BlockingModeDefault s.conf.FilteringConfig.BlockingMode = BlockingModeDefault
s.conf.FilteringConfig.EDNSClientSubnet = &EDNSClientSubnet{
Enabled: false,
}
err = s.Prepare(&s.conf) err = s.Prepare(&s.conf)
require.NoError(t, err) require.NoError(t, err)
@ -334,6 +344,9 @@ func TestServerWithProtectionDisabled(t *testing.T) {
s := createTestServer(t, &filtering.Config{}, ServerConfig{ s := createTestServer(t, &filtering.Config{}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
},
}, nil) }, nil)
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()} s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
startDeferStop(t, s) startDeferStop(t, s)
@ -438,6 +451,9 @@ func TestSafeSearch(t *testing.T) {
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
s := createTestServer(t, filterConf, forwardConf, nil) s := createTestServer(t, filterConf, forwardConf, nil)
@ -493,6 +509,11 @@ func TestInvalidRequest(t *testing.T) {
s := createTestServer(t, &filtering.Config{}, ServerConfig{ s := createTestServer(t, &filtering.Config{}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
},
}, nil) }, nil)
startDeferStop(t, s) startDeferStop(t, s)
@ -519,6 +540,9 @@ func TestBlockedRequest(t *testing.T) {
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: BlockingModeDefault, BlockingMode: BlockingModeDefault,
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
s := createTestServer(t, &filtering.Config{}, forwardConf, nil) s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
@ -544,6 +568,9 @@ func TestServerCustomClientUpstream(t *testing.T) {
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
s := createTestServer(t, &filtering.Config{}, forwardConf, nil) s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
@ -592,6 +619,11 @@ func TestBlockCNAMEProtectionEnabled(t *testing.T) {
s := createTestServer(t, &filtering.Config{}, ServerConfig{ s := createTestServer(t, &filtering.Config{}, ServerConfig{
UDPListenAddrs: []*net.UDPAddr{{}}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
},
}, nil) }, nil)
testUpstm := &aghtest.Upstream{ testUpstm := &aghtest.Upstream{
CName: testCNAMEs, CName: testCNAMEs,
@ -622,6 +654,9 @@ func TestBlockCNAME(t *testing.T) {
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: BlockingModeDefault, BlockingMode: BlockingModeDefault,
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
s := createTestServer(t, &filtering.Config{}, forwardConf, nil) s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
@ -691,6 +726,9 @@ func TestClientRulesForCNAMEMatching(t *testing.T) {
FilterHandler: func(_ net.IP, _ string, settings *filtering.Settings) { FilterHandler: func(_ net.IP, _ string, settings *filtering.Settings) {
settings.FilteringEnabled = false settings.FilteringEnabled = false
}, },
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
s := createTestServer(t, &filtering.Config{}, forwardConf, nil) s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
@ -732,6 +770,9 @@ func TestNullBlockedRequest(t *testing.T) {
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: BlockingModeNullIP, BlockingMode: BlockingModeNullIP,
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
s := createTestServer(t, &filtering.Config{}, forwardConf, nil) s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
@ -784,6 +825,9 @@ func TestBlockedCustomIP(t *testing.T) {
BlockingMode: BlockingModeCustomIP, BlockingMode: BlockingModeCustomIP,
BlockingIPv4: nil, BlockingIPv4: nil,
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"}, UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
@ -832,6 +876,9 @@ func TestBlockedByHosts(t *testing.T) {
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: BlockingModeDefault, BlockingMode: BlockingModeDefault,
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
@ -865,6 +912,9 @@ func TestBlockedBySafeBrowsing(t *testing.T) {
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
SafeBrowsingBlockHost: ans4.String(), SafeBrowsingBlockHost: ans4.String(),
ProtectionEnabled: true, ProtectionEnabled: true,
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
s := createTestServer(t, filterConf, forwardConf, nil) s := createTestServer(t, filterConf, forwardConf, nil)
@ -919,6 +969,9 @@ func TestRewrite(t *testing.T) {
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: BlockingModeDefault, BlockingMode: BlockingModeDefault,
UpstreamDNS: []string{"8.8.8.8:53"}, UpstreamDNS: []string{"8.8.8.8:53"},
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
})) }))
@ -1033,6 +1086,7 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) {
s.conf.UpstreamDNS = []string{"127.0.0.1:53"} s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
s.conf.FilteringConfig.ProtectionEnabled = true s.conf.FilteringConfig.ProtectionEnabled = true
s.conf.FilteringConfig.BlockingMode = BlockingModeDefault s.conf.FilteringConfig.BlockingMode = BlockingModeDefault
s.conf.FilteringConfig.EDNSClientSubnet = &EDNSClientSubnet{Enabled: false}
err = s.Prepare(&s.conf) err = s.Prepare(&s.conf)
require.NoError(t, err) require.NoError(t, err)
@ -1108,6 +1162,7 @@ func TestPTRResponseFromHosts(t *testing.T) {
s.conf.TCPListenAddrs = []*net.TCPAddr{{}} s.conf.TCPListenAddrs = []*net.TCPAddr{{}}
s.conf.UpstreamDNS = []string{"127.0.0.1:53"} s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
s.conf.FilteringConfig.BlockingMode = BlockingModeDefault s.conf.FilteringConfig.BlockingMode = BlockingModeDefault
s.conf.FilteringConfig.EDNSClientSubnet = &EDNSClientSubnet{Enabled: false}
err = s.Prepare(&s.conf) err = s.Prepare(&s.conf)
require.NoError(t, err) require.NoError(t, err)

View file

@ -29,6 +29,9 @@ func TestHandleDNSRequest_filterDNSResponse(t *testing.T) {
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: BlockingModeDefault, BlockingMode: BlockingModeDefault,
EDNSClientSubnet: &EDNSClientSubnet{
Enabled: false,
},
}, },
} }
filters := []filtering.Filter{{ filters := []filtering.Filter{{

View file

@ -57,7 +57,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
blockingIPv4 := s.conf.BlockingIPv4 blockingIPv4 := s.conf.BlockingIPv4
blockingIPv6 := s.conf.BlockingIPv6 blockingIPv6 := s.conf.BlockingIPv6
ratelimit := s.conf.Ratelimit ratelimit := s.conf.Ratelimit
enableEDNSClientSubnet := s.conf.EnableEDNSClientSubnet enableEDNSClientSubnet := s.conf.EDNSClientSubnet.Enabled
enableDNSSEC := s.conf.EnableDNSSEC enableDNSSEC := s.conf.EnableDNSSEC
aaaaDisabled := s.conf.AAAADisabled aaaaDisabled := s.conf.AAAADisabled
cacheSize := s.conf.CacheSize cacheSize := s.conf.CacheSize
@ -280,7 +280,7 @@ func (s *Server) setConfigRestartable(dc *jsonDNSConfig) (shouldRestart bool) {
setIfNotNil(&s.conf.LocalPTRResolvers, dc.LocalPTRUpstreams), setIfNotNil(&s.conf.LocalPTRResolvers, dc.LocalPTRUpstreams),
setIfNotNil(&s.conf.UpstreamDNSFileName, dc.UpstreamsFile), setIfNotNil(&s.conf.UpstreamDNSFileName, dc.UpstreamsFile),
setIfNotNil(&s.conf.BootstrapDNS, dc.Bootstraps), setIfNotNil(&s.conf.BootstrapDNS, dc.Bootstraps),
setIfNotNil(&s.conf.EnableEDNSClientSubnet, dc.EDNSCSEnabled), setIfNotNil(&s.conf.EDNSClientSubnet.Enabled, dc.EDNSCSEnabled),
setIfNotNil(&s.conf.CacheSize, dc.CacheSize), setIfNotNil(&s.conf.CacheSize, dc.CacheSize),
setIfNotNil(&s.conf.CacheMinTTL, dc.CacheMinTTL), setIfNotNil(&s.conf.CacheMinTTL, dc.CacheMinTTL),
setIfNotNil(&s.conf.CacheMaxTTL, dc.CacheMaxTTL), setIfNotNil(&s.conf.CacheMaxTTL, dc.CacheMaxTTL),

View file

@ -69,6 +69,7 @@ func TestDNSForwardHTTP_handleGetConfig(t *testing.T) {
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: BlockingModeDefault, BlockingMode: BlockingModeDefault,
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"}, UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
}, },
ConfigModified: func() {}, ConfigModified: func() {},
} }
@ -144,6 +145,7 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: BlockingModeDefault, BlockingMode: BlockingModeDefault,
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"}, UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
}, },
ConfigModified: func() {}, ConfigModified: func() {},
} }
@ -227,7 +229,10 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
require.True(t, ok) require.True(t, ok)
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
t.Cleanup(func() { s.conf = defaultConf }) t.Cleanup(func() {
s.conf = defaultConf
s.conf.FilteringConfig.EDNSClientSubnet.Enabled = false
})
rBody := io.NopCloser(bytes.NewReader(caseData.Req)) rBody := io.NopCloser(bytes.NewReader(caseData.Req))
var r *http.Request var r *http.Request
@ -443,6 +448,9 @@ func TestServer_handleTestUpstreaDNS(t *testing.T) {
UDPListenAddrs: []*net.UDPAddr{{}}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddrs: []*net.TCPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}},
UpstreamTimeout: upsTimeout, UpstreamTimeout: upsTimeout,
FilteringConfig: FilteringConfig{
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
},
}, nil) }, nil)
startDeferStop(t, srv) startDeferStop(t, srv)

View file

@ -22,7 +22,7 @@ import (
) )
// currentSchemaVersion is the current schema version. // currentSchemaVersion is the current schema version.
const currentSchemaVersion = 16 const currentSchemaVersion = 17
// These aliases are provided for convenience. // These aliases are provided for convenience.
type ( type (
@ -89,6 +89,7 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) {
upgradeSchema13to14, upgradeSchema13to14,
upgradeSchema14to15, upgradeSchema14to15,
upgradeSchema15to16, upgradeSchema15to16,
upgradeSchema16to17,
} }
n := 0 n := 0
@ -892,19 +893,56 @@ func upgradeSchema15to16(diskConf yobj) (err error) {
"ignored": []any{}, "ignored": []any{},
} }
k := "statistics_interval" const field = "statistics_interval"
v, has := dns[k] v, has := dns[field]
if has { if has {
stats["enabled"] = v != 0 stats["enabled"] = v != 0
stats["interval"] = v stats["interval"] = v
} }
delete(dns, k) delete(dns, field)
diskConf["statistics"] = stats diskConf["statistics"] = stats
return nil return nil
} }
// upgradeSchema16to17 performs the following changes:
//
// # BEFORE:
// 'dns':
// 'edns_client_subnet': false
//
// # AFTER:
// 'dns':
// 'edns_client_subnet':
// 'enabled': false
// 'use_custom': false
// 'custom_ip': ""
func upgradeSchema16to17(diskConf yobj) (err error) {
log.Printf("Upgrade yaml: 16 to 17")
diskConf["schema_version"] = 17
dnsVal, ok := diskConf["dns"]
if !ok {
return nil
}
dns, ok := dnsVal.(yobj)
if !ok {
return fmt.Errorf("unexpected type of dns: %T", dnsVal)
}
const field = "edns_client_subnet"
dns[field] = map[string]any{
"enabled": dns[field] == true,
"use_custom": false,
"custom_ip": "",
}
return nil
}
// TODO(a.garipov): Replace with log.Output when we port it to our logging // TODO(a.garipov): Replace with log.Output when we port it to our logging
// package. // package.
func funcName() string { func funcName() string {

View file

@ -747,3 +747,64 @@ func TestUpgradeSchema15to16(t *testing.T) {
}) })
} }
} }
func TestUpgradeSchema16to17(t *testing.T) {
const newSchemaVer = 17
defaultWantObj := yobj{
"dns": map[string]any{
"edns_client_subnet": map[string]any{
"enabled": false,
"use_custom": false,
"custom_ip": "",
},
},
"schema_version": newSchemaVer,
}
testCases := []struct {
in yobj
want yobj
name string
}{{
in: yobj{
"dns": map[string]any{
"edns_client_subnet": false,
},
},
want: defaultWantObj,
name: "basic",
}, {
in: yobj{
"dns": map[string]any{},
},
want: defaultWantObj,
name: "default_values",
}, {
in: yobj{
"dns": map[string]any{
"edns_client_subnet": true,
},
},
want: yobj{
"dns": map[string]any{
"edns_client_subnet": map[string]any{
"enabled": true,
"use_custom": false,
"custom_ip": "",
},
},
"schema_version": newSchemaVer,
},
name: "is_true",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema16to17(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}