Pull request: all: support multiple dns hosts

Updates #1401.

Squashed commit of the following:

commit a18c3f062a88ad7d7fbfacaedb893f1ca660b6dc
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Mar 22 21:55:26 2021 +0300

    home: imp code

commit 2b4a28cbf379fbc5fb168af6d8d078cab2b8bd64
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Mar 22 20:55:08 2021 +0300

    all: rm unused field

commit 5766a97dafff4acff6b909eb6303459f7991c81e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Mar 22 16:40:14 2021 +0300

    all: support multiple dns hosts
This commit is contained in:
Ainar Garipov 2021-03-23 12:32:07 +03:00
parent 3b2f5d7842
commit 5d0d32b926
11 changed files with 272 additions and 196 deletions

View File

@ -15,6 +15,7 @@ and this project adheres to
### Added ### Added
- The ability to serve DNS queries on multiple hosts and interfaces ([#1401]).
- `ips` and `text` DHCP server options ([#2385]). - `ips` and `text` DHCP server options ([#2385]).
- `SRV` records support in `$dnsrewrite` filters ([#2533]). - `SRV` records support in `$dnsrewrite` filters ([#2533]).
@ -38,6 +39,7 @@ and this project adheres to
- Go 1.14 support. - Go 1.14 support.
[#1401]: https://github.com/AdguardTeam/AdGuardHome/issues/1401
[#2385]: https://github.com/AdguardTeam/AdGuardHome/issues/2385 [#2385]: https://github.com/AdguardTeam/AdGuardHome/issues/2385
[#2412]: https://github.com/AdguardTeam/AdGuardHome/issues/2412 [#2412]: https://github.com/AdguardTeam/AdGuardHome/issues/2412
[#2498]: https://github.com/AdguardTeam/AdGuardHome/issues/2498 [#2498]: https://github.com/AdguardTeam/AdGuardHome/issues/2498

View File

@ -50,10 +50,9 @@ type Resolver interface {
// Config allows you to configure DNS filtering with New() or just change variables directly. // Config allows you to configure DNS filtering with New() or just change variables directly.
type Config struct { type Config struct {
ParentalEnabled bool `yaml:"parental_enabled"` ParentalEnabled bool `yaml:"parental_enabled"`
SafeSearchEnabled bool `yaml:"safesearch_enabled"` SafeSearchEnabled bool `yaml:"safesearch_enabled"`
SafeBrowsingEnabled bool `yaml:"safebrowsing_enabled"` SafeBrowsingEnabled bool `yaml:"safebrowsing_enabled"`
ResolverAddress string `yaml:"-"` // DNS server address
SafeBrowsingCacheSize uint `yaml:"safebrowsing_cache_size"` // (in bytes) SafeBrowsingCacheSize uint `yaml:"safebrowsing_cache_size"` // (in bytes)
SafeSearchCacheSize uint `yaml:"safesearch_cache_size"` // (in bytes) SafeSearchCacheSize uint `yaml:"safesearch_cache_size"` // (in bytes)

View File

@ -93,8 +93,8 @@ type FilteringConfig struct {
// 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 {
TLSListenAddr *net.TCPAddr `yaml:"-" json:"-"` TLSListenAddrs []*net.TCPAddr `yaml:"-" json:"-"`
QUICListenAddr *net.UDPAddr `yaml:"-" json:"-"` QUICListenAddrs []*net.UDPAddr `yaml:"-" json:"-"`
// Reject connection if the client uses server name (in SNI) that doesn't match the certificate // Reject connection if the client uses server name (in SNI) that doesn't match the certificate
StrictSNICheck bool `yaml:"strict_sni_check" json:"-"` StrictSNICheck bool `yaml:"strict_sni_check" json:"-"`
@ -121,18 +121,18 @@ type TLSConfig struct {
// DNSCryptConfig is the DNSCrypt server configuration struct. // DNSCryptConfig is the DNSCrypt server configuration struct.
type DNSCryptConfig struct { type DNSCryptConfig struct {
UDPListenAddr *net.UDPAddr UDPListenAddrs []*net.UDPAddr
TCPListenAddr *net.TCPAddr TCPListenAddrs []*net.TCPAddr
ProviderName string ProviderName string
ResolverCert *dnscrypt.Cert ResolverCert *dnscrypt.Cert
Enabled bool Enabled bool
} }
// ServerConfig represents server configuration. // ServerConfig represents server configuration.
// The zero ServerConfig is empty and ready for use. // The zero ServerConfig is empty and ready for use.
type ServerConfig struct { type ServerConfig struct {
UDPListenAddr *net.UDPAddr // UDP listen address UDPListenAddrs []*net.UDPAddr // UDP listen address
TCPListenAddr *net.TCPAddr // TCP listen address TCPListenAddrs []*net.TCPAddr // TCP listen address
UpstreamConfig *proxy.UpstreamConfig // Upstream DNS servers config UpstreamConfig *proxy.UpstreamConfig // Upstream DNS servers config
OnDNSRequest func(d *proxy.DNSContext) OnDNSRequest func(d *proxy.DNSContext)
@ -153,16 +153,16 @@ type ServerConfig struct {
// if any of ServerConfig values are zero, then default values from below are used // if any of ServerConfig values are zero, then default values from below are used
var defaultValues = ServerConfig{ var defaultValues = ServerConfig{
UDPListenAddr: &net.UDPAddr{Port: 53}, UDPListenAddrs: []*net.UDPAddr{{Port: 53}},
TCPListenAddr: &net.TCPAddr{Port: 53}, TCPListenAddrs: []*net.TCPAddr{{Port: 53}},
FilteringConfig: FilteringConfig{BlockedResponseTTL: 3600}, FilteringConfig: FilteringConfig{BlockedResponseTTL: 3600},
} }
// createProxyConfig creates and validates configuration for the main proxy // createProxyConfig creates and validates configuration for the main proxy
func (s *Server) createProxyConfig() (proxy.Config, error) { func (s *Server) createProxyConfig() (proxy.Config, error) {
proxyConfig := proxy.Config{ proxyConfig := proxy.Config{
UDPListenAddr: []*net.UDPAddr{s.conf.UDPListenAddr}, UDPListenAddr: s.conf.UDPListenAddrs,
TCPListenAddr: []*net.TCPAddr{s.conf.TCPListenAddr}, TCPListenAddr: s.conf.TCPListenAddrs,
Ratelimit: int(s.conf.Ratelimit), Ratelimit: int(s.conf.Ratelimit),
RatelimitWhitelist: s.conf.RatelimitWhitelist, RatelimitWhitelist: s.conf.RatelimitWhitelist,
RefuseAny: s.conf.RefuseAny, RefuseAny: s.conf.RefuseAny,
@ -205,8 +205,8 @@ func (s *Server) createProxyConfig() (proxy.Config, error) {
} }
if s.conf.DNSCryptConfig.Enabled { if s.conf.DNSCryptConfig.Enabled {
proxyConfig.DNSCryptUDPListenAddr = []*net.UDPAddr{s.conf.DNSCryptConfig.UDPListenAddr} proxyConfig.DNSCryptUDPListenAddr = s.conf.DNSCryptConfig.UDPListenAddrs
proxyConfig.DNSCryptTCPListenAddr = []*net.TCPAddr{s.conf.DNSCryptConfig.TCPListenAddr} proxyConfig.DNSCryptTCPListenAddr = s.conf.DNSCryptConfig.TCPListenAddrs
proxyConfig.DNSCryptProviderName = s.conf.DNSCryptConfig.ProviderName proxyConfig.DNSCryptProviderName = s.conf.DNSCryptConfig.ProviderName
proxyConfig.DNSCryptResolverCert = s.conf.DNSCryptConfig.ResolverCert proxyConfig.DNSCryptResolverCert = s.conf.DNSCryptConfig.ResolverCert
} }
@ -225,21 +225,27 @@ func (s *Server) initDefaultSettings() {
if len(s.conf.UpstreamDNS) == 0 { if len(s.conf.UpstreamDNS) == 0 {
s.conf.UpstreamDNS = defaultDNS s.conf.UpstreamDNS = defaultDNS
} }
if len(s.conf.BootstrapDNS) == 0 { if len(s.conf.BootstrapDNS) == 0 {
s.conf.BootstrapDNS = defaultBootstrap s.conf.BootstrapDNS = defaultBootstrap
} }
if len(s.conf.ParentalBlockHost) == 0 { if len(s.conf.ParentalBlockHost) == 0 {
s.conf.ParentalBlockHost = parentalBlockHost s.conf.ParentalBlockHost = parentalBlockHost
} }
if len(s.conf.SafeBrowsingBlockHost) == 0 { if len(s.conf.SafeBrowsingBlockHost) == 0 {
s.conf.SafeBrowsingBlockHost = safeBrowsingBlockHost s.conf.SafeBrowsingBlockHost = safeBrowsingBlockHost
} }
if s.conf.UDPListenAddr == nil {
s.conf.UDPListenAddr = defaultValues.UDPListenAddr if s.conf.UDPListenAddrs == nil {
s.conf.UDPListenAddrs = defaultValues.UDPListenAddrs
} }
if s.conf.TCPListenAddr == nil {
s.conf.TCPListenAddr = defaultValues.TCPListenAddr if s.conf.TCPListenAddrs == nil {
s.conf.TCPListenAddrs = defaultValues.TCPListenAddrs
} }
if len(s.conf.BlockedHosts) == 0 { if len(s.conf.BlockedHosts) == 0 {
s.conf.BlockedHosts = defaultBlockedHosts s.conf.BlockedHosts = defaultBlockedHosts
} }
@ -325,17 +331,16 @@ func (s *Server) prepareTLS(proxyConfig *proxy.Config) error {
return nil return nil
} }
if s.conf.TLSListenAddr == nil && if s.conf.TLSListenAddrs == nil && s.conf.QUICListenAddrs == nil {
s.conf.QUICListenAddr == nil {
return nil return nil
} }
if s.conf.TLSListenAddr != nil { if s.conf.TLSListenAddrs != nil {
proxyConfig.TLSListenAddr = []*net.TCPAddr{s.conf.TLSListenAddr} proxyConfig.TLSListenAddr = s.conf.TLSListenAddrs
} }
if s.conf.QUICListenAddr != nil { if s.conf.QUICListenAddrs != nil {
proxyConfig.QUICListenAddr = []*net.UDPAddr{s.conf.QUICListenAddr} proxyConfig.QUICListenAddr = s.conf.QUICListenAddrs
} }
var err error var err error

View File

@ -123,8 +123,8 @@ func createTestTLS(t *testing.T, tlsConf TLSConfig) (s *Server, certPem []byte)
_, certPem, keyPem = createServerTLSConfig(t) _, certPem, keyPem = createServerTLSConfig(t)
s = createTestServer(t, &dnsfilter.Config{}, ServerConfig{ s = createTestServer(t, &dnsfilter.Config{}, ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
}) })
tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem
@ -219,8 +219,8 @@ func sendTestMessages(t *testing.T, conn *dns.Conn) {
func TestServer(t *testing.T) { func TestServer(t *testing.T) {
s := createTestServer(t, &dnsfilter.Config{}, ServerConfig{ s := createTestServer(t, &dnsfilter.Config{}, ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
}) })
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
&aghtest.TestUpstream{ &aghtest.TestUpstream{
@ -257,8 +257,8 @@ func TestServer(t *testing.T) {
func TestServerWithProtectionDisabled(t *testing.T) { func TestServerWithProtectionDisabled(t *testing.T) {
s := createTestServer(t, &dnsfilter.Config{}, ServerConfig{ s := createTestServer(t, &dnsfilter.Config{}, ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
}) })
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
&aghtest.TestUpstream{ &aghtest.TestUpstream{
@ -281,7 +281,7 @@ func TestServerWithProtectionDisabled(t *testing.T) {
func TestDoTServer(t *testing.T) { func TestDoTServer(t *testing.T) {
s, certPem := createTestTLS(t, TLSConfig{ s, certPem := createTestTLS(t, TLSConfig{
TLSListenAddr: &net.TCPAddr{}, TLSListenAddrs: []*net.TCPAddr{{}},
}) })
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
&aghtest.TestUpstream{ &aghtest.TestUpstream{
@ -311,7 +311,7 @@ func TestDoTServer(t *testing.T) {
func TestDoQServer(t *testing.T) { func TestDoQServer(t *testing.T) {
s, _ := createTestTLS(t, TLSConfig{ s, _ := createTestTLS(t, TLSConfig{
QUICListenAddr: &net.UDPAddr{}, QUICListenAddrs: []*net.UDPAddr{{}},
}) })
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{
&aghtest.TestUpstream{ &aghtest.TestUpstream{
@ -348,8 +348,8 @@ func TestServerRace(t *testing.T) {
CacheTime: 30, CacheTime: 30,
} }
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"}, UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
@ -383,8 +383,8 @@ func TestSafeSearch(t *testing.T) {
CustomResolver: resolver, CustomResolver: resolver,
} }
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
}, },
@ -440,8 +440,8 @@ func TestSafeSearch(t *testing.T) {
func TestInvalidRequest(t *testing.T) { func TestInvalidRequest(t *testing.T) {
s := createTestServer(t, &dnsfilter.Config{}, ServerConfig{ s := createTestServer(t, &dnsfilter.Config{}, ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
}) })
startDeferStop(t, s) startDeferStop(t, s)
@ -464,8 +464,8 @@ func TestInvalidRequest(t *testing.T) {
func TestBlockedRequest(t *testing.T) { func TestBlockedRequest(t *testing.T) {
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
}, },
@ -488,8 +488,8 @@ func TestBlockedRequest(t *testing.T) {
func TestServerCustomClientUpstream(t *testing.T) { func TestServerCustomClientUpstream(t *testing.T) {
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
}, },
@ -537,8 +537,8 @@ var testIPv4 = map[string][]net.IP{
func TestBlockCNAMEProtectionEnabled(t *testing.T) { func TestBlockCNAMEProtectionEnabled(t *testing.T) {
s := createTestServer(t, &dnsfilter.Config{}, ServerConfig{ s := createTestServer(t, &dnsfilter.Config{}, ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
}) })
testUpstm := &aghtest.TestUpstream{ testUpstm := &aghtest.TestUpstream{
CName: testCNAMEs, CName: testCNAMEs,
@ -564,8 +564,8 @@ func TestBlockCNAMEProtectionEnabled(t *testing.T) {
func TestBlockCNAME(t *testing.T) { func TestBlockCNAME(t *testing.T) {
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
}, },
@ -622,8 +622,8 @@ func TestBlockCNAME(t *testing.T) {
func TestClientRulesForCNAMEMatching(t *testing.T) { func TestClientRulesForCNAMEMatching(t *testing.T) {
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
FilterHandler: func(_ net.IP, _ string, settings *dnsfilter.RequestFilteringSettings) { FilterHandler: func(_ net.IP, _ string, settings *dnsfilter.RequestFilteringSettings) {
@ -664,8 +664,8 @@ func TestClientRulesForCNAMEMatching(t *testing.T) {
func TestNullBlockedRequest(t *testing.T) { func TestNullBlockedRequest(t *testing.T) {
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: "null_ip", BlockingMode: "null_ip",
@ -707,8 +707,8 @@ func TestBlockedCustomIP(t *testing.T) {
DNSFilter: dnsfilter.New(&dnsfilter.Config{}, filters), DNSFilter: dnsfilter.New(&dnsfilter.Config{}, filters),
}) })
conf := &ServerConfig{ conf := &ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
BlockingMode: "custom_ip", BlockingMode: "custom_ip",
@ -746,8 +746,8 @@ func TestBlockedCustomIP(t *testing.T) {
func TestBlockedByHosts(t *testing.T) { func TestBlockedByHosts(t *testing.T) {
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
}, },
@ -780,8 +780,8 @@ func TestBlockedBySafeBrowsing(t *testing.T) {
SafeBrowsingEnabled: true, SafeBrowsingEnabled: true,
} }
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
SafeBrowsingBlockHost: ans4.String(), SafeBrowsingBlockHost: ans4.String(),
ProtectionEnabled: true, ProtectionEnabled: true,
@ -824,8 +824,8 @@ func TestRewrite(t *testing.T) {
s := NewServer(DNSCreateParams{DNSFilter: f}) s := NewServer(DNSCreateParams{DNSFilter: f})
assert.Nil(t, s.Prepare(&ServerConfig{ assert.Nil(t, s.Prepare(&ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{{}},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{{}},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
UpstreamDNS: []string{"8.8.8.8:53"}, UpstreamDNS: []string{"8.8.8.8:53"},
@ -1109,8 +1109,8 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) {
DHCPServer: &testDHCP{}, DHCPServer: &testDHCP{},
}) })
s.conf.UDPListenAddr = &net.UDPAddr{} s.conf.UDPListenAddrs = []*net.UDPAddr{{}}
s.conf.TCPListenAddr = &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.ProtectionEnabled = true s.conf.FilteringConfig.ProtectionEnabled = true
require.Nil(t, s.Prepare(nil)) require.Nil(t, s.Prepare(nil))
@ -1154,8 +1154,8 @@ func TestPTRResponseFromHosts(t *testing.T) {
t.Cleanup(c.AutoHosts.Close) t.Cleanup(c.AutoHosts.Close)
s := NewServer(DNSCreateParams{DNSFilter: dnsfilter.New(&c, nil)}) s := NewServer(DNSCreateParams{DNSFilter: dnsfilter.New(&c, nil)})
s.conf.UDPListenAddr = &net.UDPAddr{} s.conf.UDPListenAddrs = []*net.UDPAddr{{}}
s.conf.TCPListenAddr = &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.ProtectionEnabled = true s.conf.FilteringConfig.ProtectionEnabled = true
require.Nil(t, s.Prepare(nil)) require.Nil(t, s.Prepare(nil))

View File

@ -23,8 +23,8 @@ func TestDNSForwardHTTTP_handleGetConfig(t *testing.T) {
CacheTime: 30, CacheTime: 30,
} }
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"}, UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
@ -94,8 +94,8 @@ func TestDNSForwardHTTTP_handleSetConfig(t *testing.T) {
CacheTime: 30, CacheTime: 30,
} }
forwardConf := ServerConfig{ forwardConf := ServerConfig{
UDPListenAddr: &net.UDPAddr{}, UDPListenAddrs: []*net.UDPAddr{},
TCPListenAddr: &net.TCPAddr{}, TCPListenAddrs: []*net.TCPAddr{},
FilteringConfig: FilteringConfig{ FilteringConfig: FilteringConfig{
ProtectionEnabled: true, ProtectionEnabled: true,
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"}, UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},

View File

@ -76,8 +76,8 @@ type configuration struct {
// field ordering is important -- yaml fields will mirror ordering from here // field ordering is important -- yaml fields will mirror ordering from here
type dnsConfig struct { type dnsConfig struct {
BindHost net.IP `yaml:"bind_host"` BindHosts []net.IP `yaml:"bind_hosts"`
Port int `yaml:"port"` Port int `yaml:"port"`
// time interval for statistics (in days) // time interval for statistics (in days)
StatsInterval uint32 `yaml:"statistics_interval"` StatsInterval uint32 `yaml:"statistics_interval"`
@ -101,7 +101,7 @@ type tlsConfigSettings struct {
ForceHTTPS bool `yaml:"force_https" json:"force_https,omitempty"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect ForceHTTPS bool `yaml:"force_https" json:"force_https,omitempty"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect
PortHTTPS int `yaml:"port_https" json:"port_https,omitempty"` // HTTPS port. If 0, HTTPS will be disabled PortHTTPS int `yaml:"port_https" json:"port_https,omitempty"` // HTTPS port. If 0, HTTPS will be disabled
PortDNSOverTLS int `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"` // DNS-over-TLS port. If 0, DOT will be disabled PortDNSOverTLS int `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"` // DNS-over-TLS port. If 0, DOT will be disabled
PortDNSOverQUIC uint16 `yaml:"port_dns_over_quic" json:"port_dns_over_quic,omitempty"` // DNS-over-QUIC port. If 0, DoQ will be disabled PortDNSOverQUIC int `yaml:"port_dns_over_quic" json:"port_dns_over_quic,omitempty"` // DNS-over-QUIC port. If 0, DoQ will be disabled
// PortDNSCrypt is the port for DNSCrypt requests. If it's zero, // PortDNSCrypt is the port for DNSCrypt requests. If it's zero,
// DNSCrypt is disabled. // DNSCrypt is disabled.
@ -125,7 +125,7 @@ var config = configuration{
BetaBindPort: 0, BetaBindPort: 0,
BindHost: net.IP{0, 0, 0, 0}, BindHost: net.IP{0, 0, 0, 0},
DNS: dnsConfig{ DNS: dnsConfig{
BindHost: net.IP{0, 0, 0, 0}, BindHosts: []net.IP{{0, 0, 0, 0}},
Port: 53, Port: 53,
StatsInterval: 1, StatsInterval: 1,
FilteringConfig: dnsforward.FilteringConfig{ FilteringConfig: dnsforward.FilteringConfig{

View File

@ -17,7 +17,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/agherr" "github.com/AdguardTeam/AdGuardHome/internal/agherr"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
) )
@ -264,7 +263,7 @@ func copyInstallSettings(dst, src *configuration) {
dst.BindHost = src.BindHost dst.BindHost = src.BindHost
dst.BindPort = src.BindPort dst.BindPort = src.BindPort
dst.BetaBindPort = src.BetaBindPort dst.BetaBindPort = src.BetaBindPort
dst.DNS.BindHost = src.DNS.BindHost dst.DNS.BindHosts = src.DNS.BindHosts
dst.DNS.Port = src.DNS.Port dst.DNS.Port = src.DNS.Port
} }
@ -335,7 +334,7 @@ func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) {
Context.firstRun = false Context.firstRun = false
config.BindHost = newSettings.Web.IP config.BindHost = newSettings.Web.IP
config.BindPort = newSettings.Web.Port config.BindPort = newSettings.Web.Port
config.DNS.BindHost = newSettings.DNS.IP config.DNS.BindHosts = []net.IP{newSettings.DNS.IP}
config.DNS.Port = newSettings.DNS.Port config.DNS.Port = newSettings.DNS.Port
// TODO(e.burkov): StartMods() should be put in a separate goroutine at // TODO(e.burkov): StartMods() should be put in a separate goroutine at

View File

@ -56,11 +56,6 @@ func initDNSServer() error {
Context.queryLog = querylog.New(conf) Context.queryLog = querylog.New(conf)
filterConf := config.DNS.DnsfilterConf filterConf := config.DNS.DnsfilterConf
bindhost := config.DNS.BindHost
if config.DNS.BindHost.IsUnspecified() {
bindhost = net.IPv4(127, 0, 0, 1)
}
filterConf.ResolverAddress = net.JoinHostPort(bindhost.String(), strconv.Itoa(config.DNS.Port))
filterConf.AutoHosts = &Context.autoHosts filterConf.AutoHosts = &Context.autoHosts
filterConf.ConfigModified = onConfigModified filterConf.ConfigModified = onConfigModified
filterConf.HTTPRegister = httpRegister filterConf.HTTPRegister = httpRegister
@ -114,11 +109,51 @@ func onDNSRequest(d *proxy.DNSContext) {
} }
} }
func generateServerConfig() (newconfig dnsforward.ServerConfig, err error) { func ipsToTCPAddrs(ips []net.IP, port int) (tcpAddrs []*net.TCPAddr) {
newconfig = dnsforward.ServerConfig{ if ips == nil {
UDPListenAddr: &net.UDPAddr{IP: config.DNS.BindHost, Port: config.DNS.Port}, return nil
TCPListenAddr: &net.TCPAddr{IP: config.DNS.BindHost, Port: config.DNS.Port}, }
FilteringConfig: config.DNS.FilteringConfig,
tcpAddrs = make([]*net.TCPAddr, len(ips))
for i, ip := range ips {
tcpAddrs[i] = &net.TCPAddr{
IP: ip,
Port: port,
}
}
return tcpAddrs
}
func ipsToUDPAddrs(ips []net.IP, port int) (udpAddrs []*net.UDPAddr) {
if ips == nil {
return nil
}
udpAddrs = make([]*net.UDPAddr, len(ips))
for i, ip := range ips {
udpAddrs[i] = &net.UDPAddr{
IP: ip,
Port: port,
}
}
return udpAddrs
}
func generateServerConfig() (newConf dnsforward.ServerConfig, err error) {
dnsConf := config.DNS
hosts := dnsConf.BindHosts
for i, h := range hosts {
if h.IsUnspecified() {
hosts[i] = net.IP{127, 0, 0, 1}
}
}
newConf = dnsforward.ServerConfig{
UDPListenAddrs: ipsToUDPAddrs(hosts, dnsConf.Port),
TCPListenAddrs: ipsToTCPAddrs(hosts, dnsConf.Port),
FilteringConfig: dnsConf.FilteringConfig,
ConfigModified: onConfigModified, ConfigModified: onConfigModified,
HTTPRegister: httpRegister, HTTPRegister: httpRegister,
OnDNSRequest: onDNSRequest, OnDNSRequest: onDNSRequest,
@ -127,25 +162,19 @@ func generateServerConfig() (newconfig dnsforward.ServerConfig, err error) {
tlsConf := tlsConfigSettings{} tlsConf := tlsConfigSettings{}
Context.tls.WriteDiskConfig(&tlsConf) Context.tls.WriteDiskConfig(&tlsConf)
if tlsConf.Enabled { if tlsConf.Enabled {
newconfig.TLSConfig = tlsConf.TLSConfig newConf.TLSConfig = tlsConf.TLSConfig
newconfig.TLSConfig.ServerName = tlsConf.ServerName newConf.TLSConfig.ServerName = tlsConf.ServerName
if tlsConf.PortDNSOverTLS != 0 { if tlsConf.PortDNSOverTLS != 0 {
newconfig.TLSListenAddr = &net.TCPAddr{ newConf.TLSListenAddrs = ipsToTCPAddrs(hosts, tlsConf.PortDNSOverTLS)
IP: config.DNS.BindHost,
Port: tlsConf.PortDNSOverTLS,
}
} }
if tlsConf.PortDNSOverQUIC != 0 { if tlsConf.PortDNSOverQUIC != 0 {
newconfig.QUICListenAddr = &net.UDPAddr{ newConf.QUICListenAddrs = ipsToUDPAddrs(hosts, tlsConf.PortDNSOverQUIC)
IP: config.DNS.BindHost,
Port: int(tlsConf.PortDNSOverQUIC),
}
} }
if tlsConf.PortDNSCrypt != 0 { if tlsConf.PortDNSCrypt != 0 {
newconfig.DNSCryptConfig, err = newDNSCrypt(config.DNS.BindHost, tlsConf) newConf.DNSCryptConfig, err = newDNSCrypt(hosts, tlsConf)
if err != nil { if err != nil {
// Don't wrap the error, because it's already // Don't wrap the error, because it's already
// wrapped by newDNSCrypt. // wrapped by newDNSCrypt.
@ -154,17 +183,17 @@ func generateServerConfig() (newconfig dnsforward.ServerConfig, err error) {
} }
} }
newconfig.TLSv12Roots = Context.tlsRoots newConf.TLSv12Roots = Context.tlsRoots
newconfig.TLSCiphers = Context.tlsCiphers newConf.TLSCiphers = Context.tlsCiphers
newconfig.TLSAllowUnencryptedDOH = tlsConf.AllowUnencryptedDOH newConf.TLSAllowUnencryptedDOH = tlsConf.AllowUnencryptedDOH
newconfig.FilterHandler = applyAdditionalFiltering newConf.FilterHandler = applyAdditionalFiltering
newconfig.GetCustomUpstreamByClient = Context.clients.FindUpstreams newConf.GetCustomUpstreamByClient = Context.clients.FindUpstreams
return newconfig, nil return newConf, nil
} }
func newDNSCrypt(bindHost net.IP, tlsConf tlsConfigSettings) (dnscc dnsforward.DNSCryptConfig, err error) { func newDNSCrypt(hosts []net.IP, tlsConf tlsConfigSettings) (dnscc dnsforward.DNSCryptConfig, err error) {
if tlsConf.DNSCryptConfigFile == "" { if tlsConf.DNSCryptConfigFile == "" {
return dnscc, agherr.Error("no dnscrypt_config_file") return dnscc, agherr.Error("no dnscrypt_config_file")
} }
@ -186,21 +215,12 @@ func newDNSCrypt(bindHost net.IP, tlsConf tlsConfigSettings) (dnscc dnsforward.D
return dnscc, fmt.Errorf("creating dnscrypt cert: %w", err) return dnscc, fmt.Errorf("creating dnscrypt cert: %w", err)
} }
udpAddr := &net.UDPAddr{
IP: bindHost,
Port: tlsConf.PortDNSCrypt,
}
tcpAddr := &net.TCPAddr{
IP: bindHost,
Port: tlsConf.PortDNSCrypt,
}
return dnsforward.DNSCryptConfig{ return dnsforward.DNSCryptConfig{
UDPListenAddr: udpAddr, UDPListenAddrs: ipsToUDPAddrs(hosts, tlsConf.PortDNSCrypt),
TCPListenAddr: tcpAddr, TCPListenAddrs: ipsToTCPAddrs(hosts, tlsConf.PortDNSCrypt),
ResolverCert: cert, ResolverCert: cert,
ProviderName: rc.ProviderName, ProviderName: rc.ProviderName,
Enabled: true, Enabled: true,
}, nil }, nil
} }
@ -249,10 +269,8 @@ func getDNSEncryption() (de dnsEncryption) {
} }
// Get the list of DNS addresses the server is listening on // Get the list of DNS addresses the server is listening on
func getDNSAddresses() []string { func getDNSAddresses() (dnsAddrs []string) {
dnsAddresses := []string{} if hosts := config.DNS.BindHosts; len(hosts) == 0 || hosts[0].IsUnspecified() {
if config.DNS.BindHost.IsUnspecified() {
ifaces, e := aghnet.GetValidNetInterfacesForWeb() ifaces, e := aghnet.GetValidNetInterfacesForWeb()
if e != nil { if e != nil {
log.Error("Couldn't get network interfaces: %v", e) log.Error("Couldn't get network interfaces: %v", e)
@ -261,25 +279,29 @@ func getDNSAddresses() []string {
for _, iface := range ifaces { for _, iface := range ifaces {
for _, addr := range iface.Addresses { for _, addr := range iface.Addresses {
addDNSAddress(&dnsAddresses, addr) addDNSAddress(&dnsAddrs, addr)
} }
} }
} else { } else {
addDNSAddress(&dnsAddresses, config.DNS.BindHost) for _, h := range hosts {
addDNSAddress(&dnsAddrs, h)
}
} }
de := getDNSEncryption() de := getDNSEncryption()
if de.https != "" { if de.https != "" {
dnsAddresses = append(dnsAddresses, de.https) dnsAddrs = append(dnsAddrs, de.https)
}
if de.tls != "" {
dnsAddresses = append(dnsAddresses, de.tls)
}
if de.quic != "" {
dnsAddresses = append(dnsAddresses, de.quic)
} }
return dnsAddresses if de.tls != "" {
dnsAddrs = append(dnsAddrs, de.tls)
}
if de.quic != "" {
dnsAddrs = append(dnsAddrs, de.quic)
}
return dnsAddrs
} }
// applyAdditionalFiltering adds additional client information and settings if // applyAdditionalFiltering adds additional client information and settings if
@ -353,13 +375,13 @@ func startDNSServer() error {
} }
func reconfigureDNSServer() (err error) { func reconfigureDNSServer() (err error) {
var newconfig dnsforward.ServerConfig var newConf dnsforward.ServerConfig
newconfig, err = generateServerConfig() newConf, err = generateServerConfig()
if err != nil { if err != nil {
return fmt.Errorf("generating forwarding dns server config: %w", err) return fmt.Errorf("generating forwarding dns server config: %w", err)
} }
err = Context.dnsServer.Reconfigure(&newconfig) err = Context.dnsServer.Reconfigure(&newConf)
if err != nil { if err != nil {
return fmt.Errorf("starting forwarding dns server: %w", err) return fmt.Errorf("starting forwarding dns server: %w", err)
} }

View File

@ -13,12 +13,20 @@ import (
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
const currentSchemaVersion = 7 // used for upgrading from old configs to new config // currentSchemaVersion is the current schema version.
const currentSchemaVersion = 8
// These aliases are provided for convenience.
type (
any = interface{}
yarr = []any
yobj = map[any]any
)
// Performs necessary upgrade operations if needed // Performs necessary upgrade operations if needed
func upgradeConfig() error { func upgradeConfig() error {
// read a config file into an interface map, so we can manipulate values without losing any // read a config file into an interface map, so we can manipulate values without losing any
diskConfig := map[string]interface{}{} diskConfig := yobj{}
body, err := readConfigFile() body, err := readConfigFile()
if err != nil { if err != nil {
return err return err
@ -53,7 +61,7 @@ func upgradeConfig() error {
} }
// Upgrade from oldVersion to newVersion // Upgrade from oldVersion to newVersion
func upgradeConfigSchema(oldVersion int, diskConfig *map[string]interface{}) error { func upgradeConfigSchema(oldVersion int, diskConfig *yobj) error {
switch oldVersion { switch oldVersion {
case 0: case 0:
err := upgradeSchema0to1(diskConfig) err := upgradeSchema0to1(diskConfig)
@ -96,6 +104,11 @@ func upgradeConfigSchema(oldVersion int, diskConfig *map[string]interface{}) err
if err != nil { if err != nil {
return err return err
} }
case 7:
err := upgradeSchema7to8(diskConfig)
if err != nil {
return err
}
default: default:
err := fmt.Errorf("configuration file contains unknown schema_version, abort") err := fmt.Errorf("configuration file contains unknown schema_version, abort")
log.Println(err) log.Println(err)
@ -121,7 +134,7 @@ func upgradeConfigSchema(oldVersion int, diskConfig *map[string]interface{}) err
// The first schema upgrade: // The first schema upgrade:
// No more "dnsfilter.txt", filters are now kept in data/filters/ // No more "dnsfilter.txt", filters are now kept in data/filters/
func upgradeSchema0to1(diskConfig *map[string]interface{}) error { func upgradeSchema0to1(diskConfig *yobj) error {
log.Printf("%s(): called", funcName()) log.Printf("%s(): called", funcName())
dnsFilterPath := filepath.Join(Context.workDir, "dnsfilter.txt") dnsFilterPath := filepath.Join(Context.workDir, "dnsfilter.txt")
@ -142,7 +155,7 @@ func upgradeSchema0to1(diskConfig *map[string]interface{}) error {
// Second schema upgrade: // Second schema upgrade:
// coredns is now dns in config // coredns is now dns in config
// delete 'Corefile', since we don't use that anymore // delete 'Corefile', since we don't use that anymore
func upgradeSchema1to2(diskConfig *map[string]interface{}) error { func upgradeSchema1to2(diskConfig *yobj) error {
log.Printf("%s(): called", funcName()) log.Printf("%s(): called", funcName())
coreFilePath := filepath.Join(Context.workDir, "Corefile") coreFilePath := filepath.Join(Context.workDir, "Corefile")
@ -166,7 +179,7 @@ func upgradeSchema1to2(diskConfig *map[string]interface{}) error {
// Third schema upgrade: // Third schema upgrade:
// Bootstrap DNS becomes an array // Bootstrap DNS becomes an array
func upgradeSchema2to3(diskConfig *map[string]interface{}) error { func upgradeSchema2to3(diskConfig *yobj) error {
log.Printf("%s(): called", funcName()) log.Printf("%s(): called", funcName())
// Let's read dns configuration from diskConfig // Let's read dns configuration from diskConfig
@ -175,8 +188,8 @@ func upgradeSchema2to3(diskConfig *map[string]interface{}) error {
return fmt.Errorf("no DNS configuration in config file") return fmt.Errorf("no DNS configuration in config file")
} }
// Convert interface{} to map[string]interface{} // Convert interface{} to yobj
newDNSConfig := make(map[string]interface{}) newDNSConfig := make(yobj)
switch v := dnsConfig.(type) { switch v := dnsConfig.(type) {
case map[interface{}]interface{}: case map[interface{}]interface{}:
@ -204,7 +217,7 @@ func upgradeSchema2to3(diskConfig *map[string]interface{}) error {
} }
// Add use_global_blocked_services=true setting for existing "clients" array // Add use_global_blocked_services=true setting for existing "clients" array
func upgradeSchema3to4(diskConfig *map[string]interface{}) error { func upgradeSchema3to4(diskConfig *yobj) error {
log.Printf("%s(): called", funcName()) log.Printf("%s(): called", funcName())
(*diskConfig)["schema_version"] = 4 (*diskConfig)["schema_version"] = 4
@ -240,7 +253,7 @@ func upgradeSchema3to4(diskConfig *map[string]interface{}) error {
// - name: "..." // - name: "..."
// password: "..." // password: "..."
// ... // ...
func upgradeSchema4to5(diskConfig *map[string]interface{}) error { func upgradeSchema4to5(diskConfig *yobj) error {
log.Printf("%s(): called", funcName()) log.Printf("%s(): called", funcName())
(*diskConfig)["schema_version"] = 5 (*diskConfig)["schema_version"] = 5
@ -295,7 +308,7 @@ func upgradeSchema4to5(diskConfig *map[string]interface{}) error {
// ids: // ids:
// - 127.0.0.1 // - 127.0.0.1
// - ... // - ...
func upgradeSchema5to6(diskConfig *map[string]interface{}) error { func upgradeSchema5to6(diskConfig *yobj) error {
log.Printf("%s(): called", funcName()) log.Printf("%s(): called", funcName())
(*diskConfig)["schema_version"] = 6 (*diskConfig)["schema_version"] = 6
@ -365,7 +378,7 @@ func upgradeSchema5to6(diskConfig *map[string]interface{}) error {
// dhcpv4: // dhcpv4:
// gateway_ip: 192.168.56.1 // gateway_ip: 192.168.56.1
// ... // ...
func upgradeSchema6to7(diskConfig *map[string]interface{}) error { func upgradeSchema6to7(diskConfig *yobj) error {
log.Printf("Upgrade yaml: 6 to 7") log.Printf("Upgrade yaml: 6 to 7")
(*diskConfig)["schema_version"] = 7 (*diskConfig)["schema_version"] = 7
@ -384,7 +397,7 @@ func upgradeSchema6to7(diskConfig *map[string]interface{}) error {
return nil return nil
} }
dhcpv4 := map[string]interface{}{ dhcpv4 := yobj{
"gateway_ip": str, "gateway_ip": str,
} }
delete(dhcp, "gateway_ip") delete(dhcp, "gateway_ip")
@ -438,6 +451,44 @@ func upgradeSchema6to7(diskConfig *map[string]interface{}) error {
return nil return nil
} }
// upgradeSchema7to8 performs the following changes:
//
// # BEFORE:
// 'dns':
// 'bind_host': '127.0.0.1'
//
// # AFTER:
// 'dns':
// 'bind_hosts':
// - '127.0.0.1'
//
func upgradeSchema7to8(diskConfig *yobj) (err error) {
log.Printf("Upgrade yaml: 7 to 8")
(*diskConfig)["schema_version"] = 8
dnsVal, ok := (*diskConfig)["dns"]
if !ok {
return nil
}
dns, ok := dnsVal.(yobj)
if !ok {
return fmt.Errorf("unexpected type of dns: %T", dnsVal)
}
bindHostVal := dns["bind_host"]
bindHost, ok := bindHostVal.(string)
if !ok {
return fmt.Errorf("undexpected type of dns.bind_host: %T", bindHostVal)
}
delete(dns, "bind_host")
dns["bind_hosts"] = yarr{bindHost}
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

@ -1,18 +1,13 @@
package home package home
import ( import (
"fmt"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// any is a convenient alias for interface{}. // TODO(a.garipov): Cover all migrations, use a testdata/ dir.
type any = interface{}
// object is a convenient alias for map[string]interface{}.
type object = map[string]any
func TestUpgradeSchema1to2(t *testing.T) { func TestUpgradeSchema1to2(t *testing.T) {
diskConf := testDiskConf(1) diskConf := testDiskConf(1)
@ -25,11 +20,10 @@ func TestUpgradeSchema1to2(t *testing.T) {
_, ok := diskConf["coredns"] _, ok := diskConf["coredns"]
require.False(t, ok) require.False(t, ok)
dnsMap, ok := diskConf["dns"] newDNSConf, ok := diskConf["dns"]
require.True(t, ok) require.True(t, ok)
oldDNSConf := convertToObject(t, testDNSConf(1)) oldDNSConf := testDNSConf(1)
newDNSConf := convertToObject(t, dnsMap)
assert.Equal(t, oldDNSConf, newDNSConf) assert.Equal(t, oldDNSConf, newDNSConf)
oldExcludedEntries := []string{"coredns", "schema_version"} oldExcludedEntries := []string{"coredns", "schema_version"}
@ -49,7 +43,9 @@ func TestUpgradeSchema2to3(t *testing.T) {
dnsMap, ok := diskConf["dns"] dnsMap, ok := diskConf["dns"]
require.True(t, ok) require.True(t, ok)
newDNSConf := convertToObject(t, dnsMap) newDNSConf, ok := dnsMap.(yobj)
require.True(t, ok)
bootstrapDNS := newDNSConf["bootstrap_dns"] bootstrapDNS := newDNSConf["bootstrap_dns"]
switch v := bootstrapDNS.(type) { switch v := bootstrapDNS.(type) {
case []string: case []string:
@ -60,7 +56,7 @@ func TestUpgradeSchema2to3(t *testing.T) {
} }
excludedEntries := []string{"bootstrap_dns"} excludedEntries := []string{"bootstrap_dns"}
oldDNSConf := convertToObject(t, testDNSConf(2)) oldDNSConf := testDNSConf(2)
assertEqualExcept(t, oldDNSConf, newDNSConf, excludedEntries, excludedEntries) assertEqualExcept(t, oldDNSConf, newDNSConf, excludedEntries, excludedEntries)
excludedEntries = []string{"dns", "schema_version"} excludedEntries = []string{"dns", "schema_version"}
@ -68,29 +64,34 @@ func TestUpgradeSchema2to3(t *testing.T) {
assertEqualExcept(t, oldDiskConf, diskConf, excludedEntries, excludedEntries) assertEqualExcept(t, oldDiskConf, diskConf, excludedEntries, excludedEntries)
} }
func convertToObject(t *testing.T, oldConf any) (newConf object) { func TestUpgradeSchema7to8(t *testing.T) {
t.Helper() const host = "1.2.3.4"
oldConf := yobj{
switch v := oldConf.(type) { "dns": yobj{
case map[any]any: "bind_host": host,
newConf = make(object, len(v)) },
for key, value := range v { "schema_version": 7,
newConf[fmt.Sprint(key)] = value
}
case object:
newConf = make(object, len(v))
for key, value := range v {
newConf[key] = value
}
default:
t.Fatalf("dns configuration is not a map, got %T", oldConf)
} }
return newConf err := upgradeSchema7to8(&oldConf)
require.Nil(t, err)
require.Equal(t, oldConf["schema_version"], 8)
dnsVal, ok := oldConf["dns"]
require.True(t, ok)
newDNSConf, ok := dnsVal.(yobj)
require.True(t, ok)
newBindHosts, ok := newDNSConf["bind_hosts"].(yarr)
require.True(t, ok)
require.Len(t, newBindHosts, 1)
assert.Equal(t, host, newBindHosts[0])
} }
// assertEqualExcept removes entries from configs and compares them. // assertEqualExcept removes entries from configs and compares them.
func assertEqualExcept(t *testing.T, oldConf, newConf object, oldKeys, newKeys []string) { func assertEqualExcept(t *testing.T, oldConf, newConf yobj, oldKeys, newKeys []string) {
t.Helper() t.Helper()
for _, k := range oldKeys { for _, k := range oldKeys {
@ -103,20 +104,17 @@ func assertEqualExcept(t *testing.T, oldConf, newConf object, oldKeys, newKeys [
assert.Equal(t, oldConf, newConf) assert.Equal(t, oldConf, newConf)
} }
func testDiskConf(schemaVersion int) (diskConf object) { func testDiskConf(schemaVersion int) (diskConf yobj) {
filters := []filter{ filters := []filter{{
{ URL: "https://filters.adtidy.org/android/filters/111_optimized.txt",
URL: "https://filters.adtidy.org/android/filters/111_optimized.txt", Name: "Latvian filter",
Name: "Latvian filter", RulesCount: 100,
RulesCount: 100, }, {
}, URL: "https://easylist.to/easylistgermany/easylistgermany.txt",
{ Name: "Germany filter",
URL: "https://easylist.to/easylistgermany/easylistgermany.txt", RulesCount: 200,
Name: "Germany filter", }}
RulesCount: 200, diskConf = yobj{
},
}
diskConf = object{
"language": "en", "language": "en",
"filters": filters, "filters": filters,
"user_rules": []string{}, "user_rules": []string{},
@ -139,8 +137,8 @@ func testDiskConf(schemaVersion int) (diskConf object) {
// testDNSConf creates a DNS config for test the way gopkg.in/yaml.v2 would // testDNSConf creates a DNS config for test the way gopkg.in/yaml.v2 would
// unmarshal it. In YAML, keys aren't guaranteed to always only be strings. // unmarshal it. In YAML, keys aren't guaranteed to always only be strings.
func testDNSConf(schemaVersion int) (dnsConf map[any]any) { func testDNSConf(schemaVersion int) (dnsConf yobj) {
dnsConf = map[any]any{ dnsConf = yobj{
"port": 53, "port": 53,
"blocked_response_ttl": 10, "blocked_response_ttl": 10,
"querylog_enabled": true, "querylog_enabled": true,

View File

@ -93,7 +93,7 @@ readonly build_flags="${BUILD_FLAGS:-$out_flags $par_flags\
$v_flags $x_flags}" $v_flags $x_flags}"
# Don't use quotes with flag variables to get word splitting. # Don't use quotes with flag variables to get word splitting.
"$go" generate $v_flags $x_flags ./... "$go" generate $v_flags $x_flags ./main.go
# Don't use quotes with flag variables to get word splitting. # Don't use quotes with flag variables to get word splitting.
"$go" build --ldflags "$ldflags" $build_flags "$go" build --ldflags "$ldflags" $build_flags