Pull request: all: fix client custom upstream comments

Updates #2947.

Squashed commit of the following:

commit 498a05459b1aa00bcffee490acfeecb567025971
Merge: 6a7a2f87 21e2c419
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Apr 13 13:40:29 2021 +0300

    Merge branch 'master' into 2947-cli-ups-comment

commit 6a7a2f87cfd2bdd829b82889890511fef8d84b9b
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Apr 13 13:34:28 2021 +0300

    all: imp code, tests

commit abc0be239f69cfc3e7d0cde2fc952d9157b2cd5d
Merge: 82fb3fcb 6410feeb
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Apr 13 13:17:09 2021 +0300

    Merge branch 'master' into 2947-cli-ups-comment

commit 82fb3fcb49cbc8d439cb5959c1cb84ae49b2257e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Apr 12 22:13:41 2021 +0300

    all: fix client custom upstream comments
This commit is contained in:
Ainar Garipov 2021-04-13 13:44:29 +03:00
parent 21e2c419b9
commit 48d702f76a
10 changed files with 72 additions and 52 deletions

View File

@ -45,6 +45,7 @@ and this project adheres to
### Fixed ### Fixed
- Comment handling in clients' custom upstreams ([#2947]).
- Overwriting of DHCPv4 options when using the HTTP API ([#2927]). - Overwriting of DHCPv4 options when using the HTTP API ([#2927]).
- Assumption that MAC addresses always have the length of 6 octets ([#2828]). - Assumption that MAC addresses always have the length of 6 octets ([#2828]).
- Support for more than one `/24` subnet in DHCP ([#2541]). - Support for more than one `/24` subnet in DHCP ([#2541]).
@ -71,6 +72,7 @@ and this project adheres to
[#2838]: https://github.com/AdguardTeam/AdGuardHome/issues/2838 [#2838]: https://github.com/AdguardTeam/AdGuardHome/issues/2838
[#2889]: https://github.com/AdguardTeam/AdGuardHome/issues/2889 [#2889]: https://github.com/AdguardTeam/AdGuardHome/issues/2889
[#2927]: https://github.com/AdguardTeam/AdGuardHome/issues/2927 [#2927]: https://github.com/AdguardTeam/AdGuardHome/issues/2927
[#2947]: https://github.com/AdguardTeam/AdGuardHome/issues/2947

View File

@ -19,6 +19,18 @@ func CloneSlice(a []string) (b []string) {
return CloneSliceOrEmpty(a) return CloneSliceOrEmpty(a)
} }
// FilterOut returns a copy of strs with all strings for which f returned true
// removed.
func FilterOut(strs []string, f func(s string) (ok bool)) (filtered []string) {
for _, s := range strs {
if !f(s) {
filtered = append(filtered, s)
}
}
return filtered
}
// InSlice checks if string is in the slice of strings. // InSlice checks if string is in the slice of strings.
func InSlice(strs []string, str string) (ok bool) { func InSlice(strs []string, str string) (ok bool) {
for _, s := range strs { for _, s := range strs {
@ -30,6 +42,12 @@ func InSlice(strs []string, str string) (ok bool) {
return false return false
} }
// IsCommentOrEmpty returns true of the string starts with a "#" character or is
// an empty string.
func IsCommentOrEmpty(s string) (ok bool) {
return len(s) == 0 || s[0] == '#'
}
// SplitNext splits string by a byte and returns the first chunk skipping empty // SplitNext splits string by a byte and returns the first chunk skipping empty
// ones. Whitespaces are trimmed. // ones. Whitespaces are trimmed.
func SplitNext(s *string, sep rune) (chunk string) { func SplitNext(s *string, sep rune) (chunk string) {

View File

@ -36,6 +36,21 @@ func TestCloneSlice_family(t *testing.T) {
}) })
} }
func TestFilterOut(t *testing.T) {
strs := []string{
"1.2.3.4",
"",
"# 5.6.7.8",
}
want := []string{
"1.2.3.4",
}
got := FilterOut(strs, IsCommentOrEmpty)
assert.Equal(t, want, got)
}
func TestInSlice(t *testing.T) { func TestInSlice(t *testing.T) {
simpleStrs := []string{"1", "2", "3"} simpleStrs := []string{"1", "2", "3"}

View File

@ -289,7 +289,7 @@ func (s *Server) prepareUpstreamSettings() error {
upstreams = s.conf.UpstreamDNS upstreams = s.conf.UpstreamDNS
} }
upstreams = filterOutComments(upstreams) upstreams = aghstrings.FilterOut(upstreams, aghstrings.IsCommentOrEmpty)
upstreamConfig, err := proxy.ParseUpstreamsConfig( upstreamConfig, err := proxy.ParseUpstreamsConfig(
upstreams, upstreams,
upstream.Options{ upstream.Options{

View File

@ -295,8 +295,8 @@ func (s *Server) startLocked() error {
// faster than ordinary upstreams. // faster than ordinary upstreams.
const defaultLocalTimeout = 1 * time.Second const defaultLocalTimeout = 1 * time.Second
// collectDNSIPAddrs returns the slice of IP addresses without port number which // collectDNSIPAddrs returns IP addresses the server is listening on without
// we are listening on. For internal use only. // port numbers as a map. For internal use only.
func (s *Server) collectDNSIPAddrs() (addrs []string, err error) { func (s *Server) collectDNSIPAddrs() (addrs []string, err error) {
addrs = make([]string, len(s.conf.TCPListenAddrs)+len(s.conf.UDPListenAddrs)) addrs = make([]string, len(s.conf.TCPListenAddrs)+len(s.conf.UDPListenAddrs))
var i int var i int
@ -329,28 +329,17 @@ func (s *Server) collectDNSIPAddrs() (addrs []string, err error) {
return addrs[:i], nil return addrs[:i], nil
} }
// stringSetSubtract subtracts b from a interpreted as sets. // unit is used to show the presence of a value in a set.
func stringSetSubtract(a, b []string) (c []string) { type unit = struct{}
// unit is an object to be used as value in set.
type unit = struct{}
cSet := make(map[string]unit) // sliceToSet converts a slice of strings into a string set.
for _, k := range a { func sliceToSet(strs []string) (set map[string]unit) {
cSet[k] = unit{} set = make(map[string]unit, len(strs))
for _, s := range strs {
set[s] = unit{}
} }
for _, k := range b { return set
delete(cSet, k)
}
c = make([]string, len(cSet))
i := 0
for k := range cSet {
c[i] = k
i++
}
return c
} }
// setupResolvers initializes the resolvers for local addresses. For internal // setupResolvers initializes the resolvers for local addresses. For internal
@ -377,11 +366,17 @@ func (s *Server) setupResolvers(localAddrs []string) (err error) {
return err return err
} }
ourAddrsSet := sliceToSet(ourAddrs)
// TODO(e.burkov): The approach of subtracting sets of strings is not // TODO(e.burkov): The approach of subtracting sets of strings is not
// really applicable here since in case of listening on all network // really applicable here since in case of listening on all network
// interfaces we should check the whole interface's network to cut off // interfaces we should check the whole interface's network to cut off
// all the loopback addresses as well. // all the loopback addresses as well.
localAddrs = stringSetSubtract(localAddrs, ourAddrs) localAddrs = aghstrings.FilterOut(localAddrs, func(s string) (ok bool) {
_, ok = ourAddrsSet[s]
return ok
})
var upsConfig proxy.UpstreamConfig var upsConfig proxy.UpstreamConfig
upsConfig, err = proxy.ParseUpstreamsConfig(localAddrs, upstream.Options{ upsConfig, err = proxy.ParseUpstreamsConfig(localAddrs, upstream.Options{

View File

@ -328,7 +328,7 @@ type upstreamJSON struct {
// TODO(e.burkov): Move into aghnet or even into dnsproxy. // TODO(e.burkov): Move into aghnet or even into dnsproxy.
func ValidateUpstreams(upstreams []string) (err error) { func ValidateUpstreams(upstreams []string) (err error) {
// No need to validate comments // No need to validate comments
upstreams = filterOutComments(upstreams) upstreams = aghstrings.FilterOut(upstreams, aghstrings.IsCommentOrEmpty)
// Consider this case valid because defaultDNS will be used // Consider this case valid because defaultDNS will be used
if len(upstreams) == 0 { if len(upstreams) == 0 {
@ -510,7 +510,7 @@ func checkPrivateUpstreamExc(u upstream.Upstream) (err error) {
} }
func checkDNS(input string, bootstrap []string, ef excFunc) (err error) { func checkDNS(input string, bootstrap []string, ef excFunc) (err error) {
if !isUpstream(input) { if aghstrings.IsCommentOrEmpty(input) {
return nil return nil
} }

View File

@ -9,6 +9,7 @@ import (
"net/http/httptest" "net/http/httptest"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter" "github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
@ -149,7 +150,7 @@ func TestDNSForwardHTTTP_handleSetConfig(t *testing.T) {
wantSet: "", wantSet: "",
}, { }, {
name: "blocking_mode_bad", name: "blocking_mode_bad",
wantSet: "blocking_mode: incorrect value\n", wantSet: "blocking_mode: incorrect value",
}, { }, {
name: "ratelimit", name: "ratelimit",
wantSet: "", wantSet: "",
@ -169,17 +170,20 @@ func TestDNSForwardHTTTP_handleSetConfig(t *testing.T) {
name: "upstream_mode_fastest_addr", name: "upstream_mode_fastest_addr",
wantSet: "", wantSet: "",
}, { }, {
name: "upstream_dns_bad", name: "upstream_dns_bad",
wantSet: "wrong upstreams specification: missing port in address\n", wantSet: `wrong upstreams specification: address !!!: ` +
`missing port in address`,
}, { }, {
name: "bootstraps_bad", name: "bootstraps_bad",
wantSet: "a can not be used as bootstrap dns cause: invalid bootstrap server address: Resolver a is not eligible to be a bootstrap DNS server\n", wantSet: `a can not be used as bootstrap dns cause: ` +
`invalid bootstrap server address: ` +
`Resolver a is not eligible to be a bootstrap DNS server`,
}, { }, {
name: "cache_bad_ttl", name: "cache_bad_ttl",
wantSet: "cache_ttl_min must be less or equal than cache_ttl_max\n", wantSet: `cache_ttl_min must be less or equal than cache_ttl_max`,
}, { }, {
name: "upstream_mode_bad", name: "upstream_mode_bad",
wantSet: "upstream_mode: incorrect value\n", wantSet: `upstream_mode: incorrect value`,
}, { }, {
name: "local_ptr_upstreams_good", name: "local_ptr_upstreams_good",
wantSet: "", wantSet: "",
@ -209,7 +213,7 @@ func TestDNSForwardHTTTP_handleSetConfig(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
s.handleSetConfig(w, r) s.handleSetConfig(w, r)
assert.Equal(t, tc.wantSet, w.Body.String()) assert.Equal(t, tc.wantSet, strings.TrimSuffix(w.Body.String(), "\n"))
w.Body.Reset() w.Body.Reset()
s.handleGetConfig(w, nil) s.handleGetConfig(w, nil)

View File

@ -324,7 +324,7 @@
"upstream_dns_bad": { "upstream_dns_bad": {
"req": { "req": {
"upstream_dns": [ "upstream_dns": [
"" "!!!"
] ]
}, },
"want": { "want": {

View File

@ -67,18 +67,3 @@ func matchDNSName(dnsNames []string, sni string) bool {
} }
return false return false
} }
// Is not comment
func isUpstream(line string) bool {
return !strings.HasPrefix(line, "#")
}
func filterOutComments(lines []string) []string {
var filtered []string
for _, l := range lines {
if isUpstream(l) {
filtered = append(filtered, l)
}
}
return filtered
}

View File

@ -349,13 +349,14 @@ func (clients *clientsContainer) FindUpstreams(ip string) *proxy.UpstreamConfig
return nil return nil
} }
if len(c.Upstreams) == 0 { upstreams := aghstrings.FilterOut(c.Upstreams, aghstrings.IsCommentOrEmpty)
if len(upstreams) == 0 {
return nil return nil
} }
if c.upstreamConfig == nil { if c.upstreamConfig == nil {
conf, err := proxy.ParseUpstreamsConfig( conf, err := proxy.ParseUpstreamsConfig(
c.Upstreams, upstreams,
upstream.Options{ upstream.Options{
Bootstrap: config.DNS.BootstrapDNS, Bootstrap: config.DNS.BootstrapDNS,
Timeout: dnsforward.DefaultTimeout, Timeout: dnsforward.DefaultTimeout,