Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package dnsproxy for openSUSE:Factory checked in at 2024-04-28 21:48:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dnsproxy (Old) and /work/SRC/openSUSE:Factory/.dnsproxy.new.1880 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dnsproxy" Sun Apr 28 21:48:48 2024 rev:25 rq:1170310 version:0.71.0 Changes: -------- --- /work/SRC/openSUSE:Factory/dnsproxy/dnsproxy.changes 2024-04-23 18:55:51.249989591 +0200 +++ /work/SRC/openSUSE:Factory/.dnsproxy.new.1880/dnsproxy.changes 2024-04-29 09:07:58.061523027 +0200 @@ -1,0 +2,8 @@ +Fri Apr 26 15:54:34 UTC 2024 - Eyad Issa <[email protected]> + +- Update to version 0.71.0: + * The quic-go dependency has been updated due to issues with + QUIC and HTTP/3 upstreams on older Linux kernel versions. + * Domain specifications for top-level domains now considered when + routing the requests for unqualified names. +------------------------------------------------------------------- Old: ---- dnsproxy-0.70.0.obscpio New: ---- dnsproxy-0.71.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dnsproxy.spec ++++++ --- /var/tmp/diff_new_pack.erJnnG/_old 2024-04-29 09:07:58.673545301 +0200 +++ /var/tmp/diff_new_pack.erJnnG/_new 2024-04-29 09:07:58.673545301 +0200 @@ -17,7 +17,7 @@ Name: dnsproxy -Version: 0.70.0 +Version: 0.71.0 Release: 0 Summary: A DNS proxy server License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.erJnnG/_old 2024-04-29 09:07:58.701546320 +0200 +++ /var/tmp/diff_new_pack.erJnnG/_new 2024-04-29 09:07:58.705546466 +0200 @@ -2,7 +2,7 @@ <service name="obs_scm" mode="manual"> <param name="scm">git</param> <param name="url">https://github.com/AdguardTeam/dnsproxy.git</param> - <param name="revision">v0.70.0</param> + <param name="revision">v0.71.0</param> <param name="match-tag">*</param> <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param> <param name="versionformat">@PARENT_TAG@</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.erJnnG/_old 2024-04-29 09:07:58.725547194 +0200 +++ /var/tmp/diff_new_pack.erJnnG/_new 2024-04-29 09:07:58.725547194 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/AdguardTeam/dnsproxy.git</param> - <param name="changesrevision">7d832999a812b3f237e1b0abd35c87ef559d35a4</param></service></servicedata> + <param name="changesrevision">e35720fca466dd5b5f0110eef15cf89b4040f8f1</param></service></servicedata> (No newline at EOF) ++++++ dnsproxy-0.70.0.obscpio -> dnsproxy-0.71.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsproxy-0.70.0/README.md new/dnsproxy-0.71.0/README.md --- old/dnsproxy-0.70.0/README.md 2024-04-18 14:44:55.000000000 +0200 +++ new/dnsproxy-0.71.0/README.md 2024-04-26 13:31:22.000000000 +0200 @@ -284,34 +284,76 @@ ### Specifying upstreams for domains -You can specify upstreams that will be used for a specific domain(s). We use the dnsmasq-like syntax (see `--server` description [here](http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html)). +You can specify upstreams that will be used for a specific domain(s). We use the +dnsmasq-like syntax, decorating domains with brackets (see `--server` +[description][server-description]). **Syntax:** `[/[domain1][/../domainN]/]upstreamString` -Where `upstreamString` is one or many upstreams separated by space (e.g. `1.1.1.1` or `1.1.1.1 2.2.2.2`). +Where `upstreamString` is one or many upstreams separated by space (e.g. +`1.1.1.1` or `1.1.1.1 2.2.2.2`). -If one or more domains are specified, that upstream (`upstreamString`) is used only for those domains. Usually, it is used for private nameservers. For instance, if you have a nameserver on your network which deals with `xxx.internal.local` at `192.168.0.1` then you can specify `[/internal.local/]192.168.0.1`, and dnsproxy will send all queries to that nameserver. Everything else will be sent to the default upstreams (which are mandatory!). - -1. An empty domain specification, // has the special meaning of "unqualified names only" ie names without any dots in them. -2. More specific domains take precedence over less specific domains, so: `--upstream=[/host.com/]1.2.3.4 --upstream=[/www.host.com/]2.3.4.5` will send queries for *.host.com to 1.2.3.4, except *.www.host.com, which will go to 2.3.4.5 -3. The special server address `#` means, "use the standard servers", so: `--upstream=[/host.com/]1.2.3.4 --upstream=[/www.host.com/]#` will send queries for \*.host.com to 1.2.3.4, except \*.www.host.com which will be forwarded as usual. -4. The wildcard `*` has special meaning of "any sub-domain", so: `--upstream=[/*.host.com/]1.2.3.4` will send queries for \*.host.com to 1.2.3.4, but host.com will be forwarded to default upstreams. +If one or more domains are specified, that upstream (`upstreamString`) is used +only for those domains. Usually, it is used for private nameservers. For +instance, if you have a nameserver on your network which deals with +`xxx.internal.local` at `192.168.0.1` then you can specify +`[/internal.local/]192.168.0.1`, and dnsproxy will send all queries to that +nameserver. Everything else will be sent to the default upstreams (which are +mandatory!). + +1. An empty domain specification, `//` has the special meaning of "unqualified + names only", which will be used to resolve names with a single label in them, + or with exactly two labels in case of `DS` requests. +2. More specific domains take precedence over less specific domains, so: + `--upstream=[/host.com/]1.2.3.4 --upstream=[/www.host.com/]2.3.4.5` will send + queries for `*.host.com` to `1.2.3.4`, except `*.www.host.com`, which will go + to `2.3.4.5`. +3. The special server address `#` means, "use the common servers", so: + `--upstream=[/host.com/]1.2.3.4 --upstream=[/www.host.com/]#` will send + queries for `*.host.com` to `1.2.3.4`, except `*.www.host.com` which will be + forwarded as usual. +4. The wildcard `*` has special meaning of "any sub-domain", so: + `--upstream=[/*.host.com/]1.2.3.4` will send queries for `*.host.com` to + `1.2.3.4`, but `host.com` will be forwarded to default upstreams. **Examples** -Sends queries for `*.local` domains to `192.168.0.1:53`. Other queries are sent to `8.8.8.8:53`. -``` -./dnsproxy -u 8.8.8.8:53 -u [/local/]192.168.0.1:53 -``` +Sends requests for `*.local` domains to `192.168.0.1:53`. Other requests are +sent to `8.8.8.8:53`: -Sends queries for `*.host.com` to `1.1.1.1:53` except for `*.maps.host.com` which are sent to `8.8.8.8:53` (along with other queries). +```sh +./dnsproxy\ + -u "8.8.8.8:53"\ + -u "[/local/]192.168.0.1:53" ``` -./dnsproxy -u 8.8.8.8:53 -u [/host.com/]1.1.1.1:53 -u [/maps.host.com/]# + +Sends requests for `*.host.com` to `1.1.1.1:53` except for `*.maps.host.com` +which are sent to `8.8.8.8:53` (along with other requests): + +```sh +./dnsproxy\ + -u "8.8.8.8:53"\ + -u "[/host.com/]1.1.1.1:53"\ + -u "[/maps.host.com/]#" ``` -Sends queries for `*.host.com` to `1.1.1.1:53` except for `host.com` which is sent to `8.8.8.8:53` (along with other queries). +Sends requests for `*.host.com` to `1.1.1.1:53` except for `host.com` which is +sent to `8.8.8.8:53` (along with other requests): + +```sh +./dnsproxy\ + -u "8.8.8.8:53" + -u "[/*.host.com/]1.1.1.1:53" ``` -./dnsproxy -u 8.8.8.8:53 -u [/*.host.com/]1.1.1.1:53 + +Sends requests for `com` (and its subdomains) to `1.2.3.4:53`, requests for +other top-level domains to `1.1.1.1:53`, and all other requests to `8.8.8.8:53`: + +```sh +./dnsproxy\ + -u "8.8.8.8:53"\ + -u "[//]1.1.1.1:53"\ + -u "[/com/]1.2.3.4:53" ``` ### Specifying private rDNS upstreams @@ -328,19 +370,32 @@ **Examples** Sends queries for `*.168.192.in-addr.arpa` to `192.168.1.2`, if requested by -client from `192.168.0.0/16` subnet. Other queries answered with `NXDOMAIN`. -```shell -./dnsproxy -l 192.168.1.1 -p 53 -u 8.8.8.8 --use-private-rdns --private-rdns-upstream="192.168.1.2" --private-subnets="192.168.0.0/16" +client from `192.168.0.0/16` subnet. Other queries answered with `NXDOMAIN`: + +```sh +./dnsproxy\ + -l "0.0.0.0"\ + -u "8.8.8.8"\ + --use-private-rdns\ + --private-subnets="192.168.0.0/16" + --private-rdns-upstream="192.168.1.2"\ ``` Sends queries for `*.in-addr.arpa` to `192.168.1.2`, `*.ip6.arpa` to `fe80::1`, if requested by client within the default [RFC 6303][rfc6303] subnet set. Other -queries answered with `NXDOMAIN`. -```shell -./dnsproxy -l 192.168.1.1 -p 53 -u 8.8.8.8 --use-private-rdns --private-rdns-upstream="192.168.1.2" --private-rdns-upstream="[/ip6.arpa/]fe80::1" +queries answered with `NXDOMAIN`: + +```sh +./dnsproxy\ + -l "0.0.0.0"\ + -u 8.8.8.8\ + --use-private-rdns\ + --private-rdns-upstream="192.168.1.2"\ + --private-rdns-upstream="[/ip6.arpa/]fe80::1" ``` [rfc6303]: https://datatracker.ietf.org/doc/html/rfc6303 +[server-description]: http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html ### EDNS Client Subnet diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsproxy-0.70.0/go.mod new/dnsproxy-0.71.0/go.mod --- old/dnsproxy-0.70.0/go.mod 2024-04-18 14:44:55.000000000 +0200 +++ new/dnsproxy-0.71.0/go.mod 2024-04-26 13:31:22.000000000 +0200 @@ -11,7 +11,8 @@ github.com/jessevdk/go-flags v1.5.0 github.com/miekg/dns v1.1.58 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/quic-go/quic-go v0.42.0 + // TODO(a.garipov): Update to a tag when released. + github.com/quic-go/quic-go v0.42.1-0.20240424141022-12aa63824c7f github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 golang.org/x/net v0.24.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsproxy-0.70.0/go.sum new/dnsproxy-0.71.0/go.sum --- old/dnsproxy-0.70.0/go.sum 2024-04-18 14:44:55.000000000 +0200 +++ new/dnsproxy-0.71.0/go.sum 2024-04-26 13:31:22.000000000 +0200 @@ -46,8 +46,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM= -github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= +github.com/quic-go/quic-go v0.42.1-0.20240424141022-12aa63824c7f h1:L7x60Z6AW2giF/SvbDpMglGHJxtmFJV03khPwXLDScU= +github.com/quic-go/quic-go v0.42.1-0.20240424141022-12aa63824c7f/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsproxy-0.70.0/proxy/proxy.go new/dnsproxy-0.71.0/proxy/proxy.go --- old/dnsproxy-0.70.0/proxy/proxy.go 2024-04-18 14:44:55.000000000 +0200 +++ new/dnsproxy-0.71.0/proxy/proxy.go 2024-04-26 13:31:22.000000000 +0200 @@ -55,11 +55,6 @@ ProtoDNSCrypt Proto = "dnscrypt" ) -const ( - // UnqualifiedNames is reserved name for "unqualified names only", ie names without dots - UnqualifiedNames = "unqualified_names" -) - // Proxy combines the proxy server state and configuration. It must not be used // until initialized with [Proxy.Init]. // diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsproxy-0.70.0/proxy/server_https_test.go new/dnsproxy-0.71.0/proxy/server_https_test.go --- old/dnsproxy-0.70.0/proxy/server_https_test.go 2024-04-18 14:44:55.000000000 +0200 +++ new/dnsproxy-0.71.0/proxy/server_https_test.go 2024-04-26 13:31:22.000000000 +0200 @@ -438,7 +438,7 @@ return quic.DialAddrEarly(ctx, addr, tlsCfg, cfg) }, TLSClientConfig: tlsClientConfig, - QuicConfig: &quic.Config{}, + QUICConfig: &quic.Config{}, DisableCompression: true, } } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsproxy-0.70.0/proxy/upstreams.go new/dnsproxy-0.71.0/proxy/upstreams.go --- old/dnsproxy-0.70.0/proxy/upstreams.go 2024-04-18 14:44:55.000000000 +0200 +++ new/dnsproxy-0.71.0/proxy/upstreams.go 2024-04-26 13:31:22.000000000 +0200 @@ -14,15 +14,17 @@ "github.com/AdguardTeam/golibs/netutil" ) -// UpstreamConfig is a wrapper for a list of default upstreams, a map of -// reserved domains and corresponding upstreams. +// UnqualifiedNames is a key for [UpstreamConfig.DomainReservedUpstreams] map to +// specify the upstreams only used for resolving domain names consisting of a +// single label. +const UnqualifiedNames = "unqualified_names" + +// UpstreamConfig maps domain names to upstreams. type UpstreamConfig struct { - // DomainReservedUpstreams is a map of reserved domains and lists of - // corresponding upstreams. + // DomainReservedUpstreams maps the domains to the upstreams. DomainReservedUpstreams map[string][]upstream.Upstream - // SpecifiedDomainUpstreams is a map of excluded domains and lists of - // corresponding upstreams. + // SpecifiedDomainUpstreams maps the specific domain names to the upstreams. SpecifiedDomainUpstreams map[string][]upstream.Upstream // SubdomainExclusions is set of domains with subdomains exclusions. @@ -364,44 +366,49 @@ return errors.Join(errs...) } -// getUpstreamsForDomain looks for a domain in the reserved domains map and -// returns a list of corresponding upstreams. It returns default upstreams list -// if the domain was not found in the map. More specific domains take priority -// over less specific domains. For example, take a map that contains the -// following keys: host.com and www.host.com. If we are looking for domain -// mail.host.com, this method will return value of host.com key. If we are -// looking for domain www.host.com, this method will return value of the -// www.host.com key. If a more specific domain value is nil, it means that the -// domain was excluded and should be exchanged with default upstreams. -func (uc *UpstreamConfig) getUpstreamsForDomain(host string) (ups []upstream.Upstream) { +// getUpstreamsForDomain returns the upstreams specified for resolving fqdn. It +// always returns the default set of upstreams if the domain is not reserved for +// any other upstreams. +// +// More specific domains take priority over less specific ones. For example, if +// the upstreams specified for the following domains: +// +// - host.com +// - www.host.com +// +// The request for mail.host.com will be resolved using the upstreams specified +// for host.com. +func (uc *UpstreamConfig) getUpstreamsForDomain(fqdn string) (ups []upstream.Upstream) { if len(uc.DomainReservedUpstreams) == 0 { return uc.Upstreams } - dotsCount := strings.Count(host, ".") - if dotsCount < 2 { - host = UnqualifiedNames - } else { - host = strings.ToLower(host) - if uc.SubdomainExclusions.Has(host) { - return uc.lookupSubdomainExclusion(host) + var ok bool + fqdn = strings.ToLower(fqdn) + if strings.Count(fqdn, ".") < 2 { + ups, ok = uc.lookupUpstreams(fqdn) + if ok { + return ups } + + fqdn = UnqualifiedNames + } else if uc.SubdomainExclusions.Has(fqdn) { + return uc.lookupSubdomainExclusion(fqdn) } - for host != "" { - var ok bool - if ups, ok = uc.lookupUpstreams(host); ok { + for fqdn != "" { + if ups, ok = uc.lookupUpstreams(fqdn); ok { return ups } - _, host, _ = strings.Cut(host, ".") + _, fqdn, _ = strings.Cut(fqdn, ".") } return uc.Upstreams } // getUpstreamsForDS is like [getUpstreamsForDomain], but intended for DS -// queries only, so that it matches the host without the first label. +// queries only, so that it matches fqdn without the first label. // // A DS RRset SHOULD be present at a delegation point when the child zone is // signed. The DS RRset MAY contain multiple records, each referencing a public @@ -409,13 +416,13 @@ // in a zone MUST be signed, and DS RRsets MUST NOT appear at a zone's apex. // // See https://datatracker.ietf.org/doc/html/rfc4035#section-2.4 -func (uc *UpstreamConfig) getUpstreamsForDS(host string) (ups []upstream.Upstream) { - _, host, found := strings.Cut(host, ".") - if !found { +func (uc *UpstreamConfig) getUpstreamsForDS(fqdn string) (ups []upstream.Upstream) { + _, fqdn, _ = strings.Cut(fqdn, ".") + if fqdn == "" { return uc.Upstreams } - return uc.getUpstreamsForDomain(host) + return uc.getUpstreamsForDomain(fqdn) } // lookupSubdomainExclusion returns upstreams for the host from subdomain @@ -436,7 +443,7 @@ return uc.Upstreams } -// lookupUpstreams returns upstreams for a domain name. Returns default +// lookupUpstreams returns upstreams for a domain name. It returns default // upstream list for domain name excluded by domain reserved upstreams. func (uc *UpstreamConfig) lookupUpstreams(name string) (ups []upstream.Upstream, ok bool) { ups, ok = uc.DomainReservedUpstreams[name] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsproxy-0.70.0/proxy/upstreams_internal_test.go new/dnsproxy-0.71.0/proxy/upstreams_internal_test.go --- old/dnsproxy-0.70.0/proxy/upstreams_internal_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/dnsproxy-0.71.0/proxy/upstreams_internal_test.go 2024-04-26 13:31:22.000000000 +0200 @@ -0,0 +1,482 @@ +package proxy + +import ( + "testing" + "time" + + "github.com/AdguardTeam/dnsproxy/upstream" + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TODO(e.burkov): Call [testing.T.Parallel] in this file. + +// Domains specifications and their questions used in tests of [UpstreamConfig]. +const ( + unqualifiedFQDN = "unqualified." + unspecifiedFQDN = "unspecified.domain." + + topLevelDomain = "example" + topLevelFQDN = topLevelDomain + "." + + firstLevelDomain = "name." + topLevelDomain + firstLevelFQDN = firstLevelDomain + "." + + subDomain = "sub." + firstLevelDomain + subFQDN = subDomain + "." + + generalDomain = "general." + firstLevelDomain + generalFQDN = generalDomain + "." + + wildcardDomain = "*." + firstLevelDomain + anotherSubFQDN = "another." + firstLevelDomain + "." +) + +// Upstream URLs used in tests of [UpstreamConfig]. +const ( + generalUpstream = "tcp://general.upstream:53" + unqualifiedUpstream = "tcp://unqualified.upstream:53" + tldUpstream = "tcp://tld.upstream:53" + domainUpstream = "tcp://domain.upstream:53" + wildcardUpstream = "tcp://wildcard.upstream:53" + subdomainUpstream = "tcp://subdomain.upstream:53" +) + +// testUpstreamConfigLines is the common set of upstream configurations used in +// tests of [UpstreamConfig]. +var testUpstreamConfigLines = []string{ + generalUpstream, + "[//]" + unqualifiedUpstream, + "[/" + topLevelDomain + "/]" + tldUpstream, + "[/" + firstLevelDomain + "/]" + domainUpstream, + "[/" + wildcardDomain + "/]" + wildcardUpstream, + "[/" + generalDomain + "/]#", + "[/" + subDomain + "/]" + subdomainUpstream, +} + +func TestUpstreamConfig_GetUpstreamsForDomain(t *testing.T) { + t.Parallel() + + config, err := ParseUpstreamsConfig(testUpstreamConfigLines, nil) + require.NoError(t, err) + + testCases := []struct { + name string + in string + want []string + }{{ + name: "unspecified", + in: unspecifiedFQDN, + want: []string{generalUpstream}, + }, { + name: "unqualified", + in: unqualifiedFQDN, + want: []string{unqualifiedUpstream}, + }, { + name: "tld", + in: topLevelFQDN, + want: []string{tldUpstream}, + }, { + name: "unspecified_subdomain", + in: unspecifiedFQDN + topLevelFQDN, + want: []string{tldUpstream}, + }, { + name: "domain", + in: firstLevelFQDN, + want: []string{domainUpstream}, + }, { + name: "wildcard", + in: anotherSubFQDN, + want: []string{wildcardUpstream}, + }, { + name: "general", + in: generalFQDN, + want: []string{generalUpstream}, + }, { + name: "subdomain", + in: subFQDN, + want: []string{subdomainUpstream}, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + ups := config.getUpstreamsForDomain(tc.in) + assertUpstreamsAddrs(t, ups, tc.want) + }) + } +} + +func TestUpstreamConfig_GetUpstreamsForDS(t *testing.T) { + t.Parallel() + + config, err := ParseUpstreamsConfig(testUpstreamConfigLines, nil) + require.NoError(t, err) + + testCases := []struct { + name string + in string + want []string + }{{ + name: "unspecified", + in: unspecifiedFQDN, + want: []string{unqualifiedUpstream}, + }, { + name: "unqualified", + in: unqualifiedFQDN, + want: []string{generalUpstream}, + }, { + name: "tld", + in: topLevelFQDN, + want: []string{generalUpstream}, + }, { + name: "unspecified_subdomain", + in: unspecifiedFQDN + topLevelFQDN, + want: []string{tldUpstream}, + }, { + name: "domain", + in: firstLevelFQDN, + want: []string{tldUpstream}, + }, { + name: "wildcard", + in: anotherSubFQDN, + want: []string{domainUpstream}, + }, { + name: "general", + in: "label." + generalFQDN, + want: []string{generalUpstream}, + }, { + name: "subdomain", + in: "label." + subFQDN, + want: []string{subdomainUpstream}, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + ups := config.getUpstreamsForDS(tc.in) + assertUpstreamsAddrs(t, ups, tc.want) + }) + } +} + +func TestUpstreamConfig_Validate(t *testing.T) { + testCases := []struct { + name string + wantErr error + in []string + }{{ + name: "empty", + wantErr: upstream.ErrNoUpstreams, + in: []string{}, + }, { + name: "nil", + wantErr: upstream.ErrNoUpstreams, + in: nil, + }, { + name: "valid", + wantErr: nil, + in: []string{ + "udp://upstream.example:53", + }, + }, { + name: "no_default", + wantErr: errors.Error("no default upstreams specified"), + in: []string{ + "[/domain.example/]udp://upstream.example:53", + "[/another.domain.example/]#", + }, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + c, err := ParseUpstreamsConfig(tc.in, nil) + require.NoError(t, err) + + assert.ErrorIs(t, c.validate(), tc.wantErr) + }) + } + + t.Run("actual_nil", func(t *testing.T) { + assert.ErrorIs(t, (*UpstreamConfig)(nil).validate(), errors.Error("upstream config is nil")) + }) +} + +func TestValidatePrivateConfig(t *testing.T) { + ss := netutil.SubnetSetFunc(netutil.IsLocallyServed) + + testCases := []struct { + name string + wantErr string + u string + }{{ + name: "success_address", + wantErr: ``, + u: "[/1.0.0.127.in-addr.arpa/]#", + }, { + name: "success_subnet", + wantErr: ``, + u: "[/127.in-addr.arpa/]#", + }, { + name: "success_v4_family", + wantErr: ``, + u: "[/in-addr.arpa/]#", + }, { + name: "success_v6_family", + wantErr: ``, + u: "[/ip6.arpa/]#", + }, { + name: "bad_arpa_domain", + wantErr: `bad arpa domain name "arpa": not a reversed ip network`, + u: "[/arpa/]#", + }, { + name: "not_arpa_subnet", + wantErr: `bad arpa domain name "hello.world": not a reversed ip network`, + u: "[/hello.world/]#", + }, { + name: "non-private_arpa_address", + wantErr: `reversed subnet in "1.2.3.4.in-addr.arpa." is not private`, + u: "[/1.2.3.4.in-addr.arpa/]#", + }, { + name: "non-private_arpa_subnet", + wantErr: `reversed subnet in "128.in-addr.arpa." is not private`, + u: "[/128.in-addr.arpa/]#", + }, { + name: "several_bad", + wantErr: `reversed subnet in "1.2.3.4.in-addr.arpa." is not private` + + "\n" + `bad arpa domain name "non.arpa": not a reversed ip network`, + u: "[/non.arpa/1.2.3.4.in-addr.arpa/127.in-addr.arpa/]#", + }, { + name: "partial_good", + wantErr: "", + u: "[/a.1.2.3.10.in-addr.arpa/a.10.in-addr.arpa/]#", + }} + + for _, tc := range testCases { + set := []string{"192.168.0.1", tc.u} + + t.Run(tc.name, func(t *testing.T) { + upsConf, err := ParseUpstreamsConfig(set, nil) + require.NoError(t, err) + + testutil.AssertErrorMsg(t, tc.wantErr, ValidatePrivateConfig(upsConf, ss)) + }) + } +} + +func TestGetUpstreamsForDomainWithoutDuplicates(t *testing.T) { + upstreams := []string{"[/example.com/]1.1.1.1", "[/example.org/]1.1.1.1"} + config, err := ParseUpstreamsConfig( + upstreams, + &upstream.Options{ + InsecureSkipVerify: false, + Bootstrap: nil, + Timeout: 1 * time.Second, + }, + ) + assert.NoError(t, err) + assert.Len(t, config.Upstreams, 0) + assert.Len(t, config.DomainReservedUpstreams, 2) + + u1 := config.DomainReservedUpstreams["example.com."][0] + u2 := config.DomainReservedUpstreams["example.org."][0] + + // Check that the very same Upstream instance is used for both domains. + assert.Same(t, u1, u2) +} + +func TestGetUpstreamsForDomain_wildcards(t *testing.T) { + conf := []string{ + "0.0.0.1", + "[/a.x/]0.0.0.2", + "[/*.a.x/]0.0.0.3", + "[/b.a.x/]0.0.0.4", + "[/*.b.a.x/]0.0.0.5", + "[/*.x.z/]0.0.0.6", + "[/c.b.a.x/]#", + } + + uconf, err := ParseUpstreamsConfig(conf, nil) + require.NoError(t, err) + + testCases := []struct { + name string + in string + want []string + }{{ + name: "default", + in: "d.x.", + want: []string{"0.0.0.1:53"}, + }, { + name: "specified_one", + in: "a.x.", + want: []string{"0.0.0.2:53"}, + }, { + name: "wildcard", + in: "c.a.x.", + want: []string{"0.0.0.3:53"}, + }, { + name: "specified_two", + in: "b.a.x.", + want: []string{"0.0.0.4:53"}, + }, { + name: "wildcard_two", + in: "d.b.a.x.", + want: []string{"0.0.0.5:53"}, + }, { + name: "specified_three", + in: "c.b.a.x.", + want: []string{"0.0.0.1:53"}, + }, { + name: "specified_four", + in: "d.c.b.a.x.", + want: []string{"0.0.0.1:53"}, + }, { + name: "unspecified_wildcard", + in: "x.z.", + want: []string{"0.0.0.1:53"}, + }, { + name: "unspecified_wildcard_sub", + in: "a.x.z.", + want: []string{"0.0.0.6:53"}, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ups := uconf.getUpstreamsForDomain(tc.in) + assertUpstreamsAddrs(t, ups, tc.want) + }) + } +} + +func TestGetUpstreamsForDomain_sub_wildcards(t *testing.T) { + conf := []string{ + "0.0.0.1", + "[/a.x/]0.0.0.2", + "[/*.a.x/]0.0.0.3", + "[/*.b.a.x/]0.0.0.5", + } + + uconf, err := ParseUpstreamsConfig(conf, nil) + require.NoError(t, err) + + testCases := []struct { + name string + in string + want []string + }{{ + name: "specified", + in: "a.x.", + want: []string{"0.0.0.2:53"}, + }, { + name: "wildcard", + in: "c.a.x.", + want: []string{"0.0.0.3:53"}, + }, { + name: "sub_spec_ignore", + in: "b.a.x.", + want: []string{"0.0.0.3:53"}, + }, { + name: "sub_spec_wildcard", + in: "d.b.a.x.", + want: []string{"0.0.0.5:53"}, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ups := uconf.getUpstreamsForDomain(tc.in) + assertUpstreamsAddrs(t, ups, tc.want) + }) + } +} + +func TestGetUpstreamsForDomain_default_wildcards(t *testing.T) { + conf := []string{ + "127.0.0.1:5301", + "[/example.org/]127.0.0.1:5302", + "[/*.example.org/]127.0.0.1:5303", + "[/www.example.org/]127.0.0.1:5304", + "[/*.www.example.org/]#", + } + + uconf, err := ParseUpstreamsConfig(conf, nil) + require.NoError(t, err) + + testCases := []struct { + name string + in string + want []string + }{{ + name: "domain", + in: "example.org.", + want: []string{"127.0.0.1:5302"}, + }, { + name: "sub_wildcard", + in: "sub.example.org.", + want: []string{"127.0.0.1:5303"}, + }, { + name: "spec_sub", + in: "www.example.org.", + want: []string{"127.0.0.1:5304"}, + }, { + name: "def_wildcard", + in: "abc.www.example.org.", + want: []string{"127.0.0.1:5301"}, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ups := uconf.getUpstreamsForDomain(tc.in) + assertUpstreamsAddrs(t, ups, tc.want) + }) + } +} + +// upsSink is the typed sink variable for the result of benchmarked function. +var upsSink []upstream.Upstream + +func BenchmarkGetUpstreamsForDomain(b *testing.B) { + upstreams := []string{ + "[/google.com/local/]4.3.2.1", + "[/www.google.com//]1.2.3.4", + "[/maps.google.com/]#", + "[/www.google.com/]tls://1.1.1.1", + } + + config, _ := ParseUpstreamsConfig( + upstreams, + &upstream.Options{ + InsecureSkipVerify: false, + Bootstrap: nil, + Timeout: 1 * time.Second, + }, + ) + + domains := []string{ + "www.google.com.", + "www2.google.com.", + "internal.local.", + "google.", + "maps.google.com.", + } + + l := len(domains) + for i := range b.N { + upsSink = config.getUpstreamsForDomain(domains[i%l]) + } +} + +// assertUpstreamsAddrs checks the addresses of ups to exactly match want. +func assertUpstreamsAddrs(tb testing.TB, ups []upstream.Upstream, want []string) { + tb.Helper() + + require.Len(tb, ups, len(want)) + for i, up := range ups { + assert.Equalf(tb, want[i], up.Address(), "at index %d", i) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsproxy-0.70.0/proxy/upstreams_test.go new/dnsproxy-0.71.0/proxy/upstreams_test.go --- old/dnsproxy-0.70.0/proxy/upstreams_test.go 2024-04-18 14:44:55.000000000 +0200 +++ new/dnsproxy-0.71.0/proxy/upstreams_test.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,446 +0,0 @@ -package proxy - -import ( - "testing" - "time" - - "github.com/AdguardTeam/dnsproxy/upstream" - "github.com/AdguardTeam/golibs/errors" - "github.com/AdguardTeam/golibs/netutil" - "github.com/AdguardTeam/golibs/testutil" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -// TODO(e.burkov): Call [testing.T.Parallel] in this file. - -func TestUpstreamConfig_GetUpstreamsForDomain(t *testing.T) { - upstreams := []string{ - "[/google.com/local/]4.3.2.1", - "[/www.google.com//]1.2.3.4", - "[/maps.google.com/]#", - "[/www.google.com/]tls://1.1.1.1", - "[/_acme-challenge.example.org/]#", - "[/example.com/]1.1.1.1 2.2.2.2 3.3.3.3", - } - - config, err := ParseUpstreamsConfig( - upstreams, - &upstream.Options{ - InsecureSkipVerify: false, - Bootstrap: nil, - Timeout: 1 * time.Second, - }, - ) - require.NoError(t, err) - - testCases := []struct { - name string - in string - want []string - }{{ - name: "direct_match", - in: "www.google.com.", - want: []string{"1.2.3.4:53", "tls://1.1.1.1:853"}, - }, { - name: "subdomain_match", - in: "www2.google.com.", - want: []string{"4.3.2.1:53"}, - }, { - name: "second_subdomain_match", - in: "internal.local.", - want: []string{"4.3.2.1:53"}, - }, { - name: "unqualified_match", - in: "google.", - want: []string{"1.2.3.4:53"}, - }, { - name: "default", - in: "_acme-challenge.example.org.", - want: []string{}, - }, { - name: "another_default", - in: "maps.google.com.", - want: []string{}, - }, { - name: "multiple_reserved", - in: "example.com.", - want: []string{"1.1.1.1:53", "2.2.2.2:53", "3.3.3.3:53"}, - }} - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ups := config.getUpstreamsForDomain(tc.in) - assertUpstreamsForDomain(t, ups, tc.want) - }) - } -} - -func TestUpstreamConfig_GetUpstreamsForDS(t *testing.T) { - upstreams := []string{ - "[/google.com/local/]4.3.2.1", - "[/www.google.com//]1.2.3.4", - "[/maps.google.com/]#", - "[/www.google.com/]tls://1.1.1.1", - "[/_acme-challenge.example.org/]#", - } - - config, err := ParseUpstreamsConfig( - upstreams, - &upstream.Options{ - InsecureSkipVerify: false, - Timeout: 1 * time.Second, - }, - ) - require.NoError(t, err) - - testCases := []struct { - name string - in string - want []string - }{{ - name: "direct_match", - in: "www.google.com.", - want: []string{"4.3.2.1:53"}, - }, { - name: "subdomain_match", - in: "abc.www.google.com.", - want: []string{"1.2.3.4:53", "tls://1.1.1.1:853"}, - }, { - name: "unqualified_match", - in: "internal.local.", - want: []string{"1.2.3.4:53"}, - }, { - name: "more_unqualified_match", - in: "google.", - want: []string{"1.2.3.4:53"}, - }, { - name: "default", - in: "_acme-challenge.example.org.", - want: []string{}, - }} - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ups := config.getUpstreamsForDS(tc.in) - assertUpstreamsForDomain(t, ups, tc.want) - }) - } -} - -func TestUpstreamConfig_Validate(t *testing.T) { - testCases := []struct { - name string - wantValidateErr error - in []string - }{{ - name: "empty", - wantValidateErr: upstream.ErrNoUpstreams, - in: []string{}, - }, { - name: "nil", - wantValidateErr: upstream.ErrNoUpstreams, - in: nil, - }, { - name: "valid", - wantValidateErr: nil, - in: []string{ - "udp://upstream.example:53", - }, - }, { - name: "no_default", - wantValidateErr: errors.Error("no default upstreams specified"), - in: []string{ - "[/domain.example/]udp://upstream.example:53", - "[/another.domain.example/]#", - }, - }} - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - c, err := ParseUpstreamsConfig(tc.in, nil) - require.NoError(t, err) - - assert.ErrorIs(t, c.validate(), tc.wantValidateErr) - }) - } - - t.Run("actual_nil", func(t *testing.T) { - assert.ErrorIs(t, (*UpstreamConfig)(nil).validate(), errors.Error("upstream config is nil")) - }) -} - -func TestValidatePrivateConfig(t *testing.T) { - ss := netutil.SubnetSetFunc(netutil.IsLocallyServed) - - testCases := []struct { - name string - wantErr string - u string - }{{ - name: "success_address", - wantErr: ``, - u: "[/1.0.0.127.in-addr.arpa/]#", - }, { - name: "success_subnet", - wantErr: ``, - u: "[/127.in-addr.arpa/]#", - }, { - name: "success_v4_family", - wantErr: ``, - u: "[/in-addr.arpa/]#", - }, { - name: "success_v6_family", - wantErr: ``, - u: "[/ip6.arpa/]#", - }, { - name: "bad_arpa_domain", - wantErr: `bad arpa domain name "arpa": not a reversed ip network`, - u: "[/arpa/]#", - }, { - name: "not_arpa_subnet", - wantErr: `bad arpa domain name "hello.world": not a reversed ip network`, - u: "[/hello.world/]#", - }, { - name: "non-private_arpa_address", - wantErr: `reversed subnet in "1.2.3.4.in-addr.arpa." is not private`, - u: "[/1.2.3.4.in-addr.arpa/]#", - }, { - name: "non-private_arpa_subnet", - wantErr: `reversed subnet in "128.in-addr.arpa." is not private`, - u: "[/128.in-addr.arpa/]#", - }, { - name: "several_bad", - wantErr: `reversed subnet in "1.2.3.4.in-addr.arpa." is not private` + - "\n" + `bad arpa domain name "non.arpa": not a reversed ip network`, - u: "[/non.arpa/1.2.3.4.in-addr.arpa/127.in-addr.arpa/]#", - }, { - name: "partial_good", - wantErr: "", - u: "[/a.1.2.3.10.in-addr.arpa/a.10.in-addr.arpa/]#", - }} - - for _, tc := range testCases { - set := []string{"192.168.0.1", tc.u} - - t.Run(tc.name, func(t *testing.T) { - upsConf, err := ParseUpstreamsConfig(set, nil) - require.NoError(t, err) - - testutil.AssertErrorMsg(t, tc.wantErr, ValidatePrivateConfig(upsConf, ss)) - }) - } -} - -func TestGetUpstreamsForDomainWithoutDuplicates(t *testing.T) { - upstreams := []string{"[/example.com/]1.1.1.1", "[/example.org/]1.1.1.1"} - config, err := ParseUpstreamsConfig( - upstreams, - &upstream.Options{ - InsecureSkipVerify: false, - Bootstrap: nil, - Timeout: 1 * time.Second, - }, - ) - assert.NoError(t, err) - assert.Len(t, config.Upstreams, 0) - assert.Len(t, config.DomainReservedUpstreams, 2) - - u1 := config.DomainReservedUpstreams["example.com."][0] - u2 := config.DomainReservedUpstreams["example.org."][0] - - // Check that the very same Upstream instance is used for both domains. - assert.Same(t, u1, u2) -} - -func TestGetUpstreamsForDomain_wildcards(t *testing.T) { - conf := []string{ - "0.0.0.1", - "[/a.x/]0.0.0.2", - "[/*.a.x/]0.0.0.3", - "[/b.a.x/]0.0.0.4", - "[/*.b.a.x/]0.0.0.5", - "[/*.x.z/]0.0.0.6", - "[/c.b.a.x/]#", - } - - uconf, err := ParseUpstreamsConfig(conf, nil) - require.NoError(t, err) - - testCases := []struct { - name string - in string - want []string - }{{ - name: "default", - in: "d.x.", - want: []string{"0.0.0.1:53"}, - }, { - name: "specified_one", - in: "a.x.", - want: []string{"0.0.0.2:53"}, - }, { - name: "wildcard", - in: "c.a.x.", - want: []string{"0.0.0.3:53"}, - }, { - name: "specified_two", - in: "b.a.x.", - want: []string{"0.0.0.4:53"}, - }, { - name: "wildcard_two", - in: "d.b.a.x.", - want: []string{"0.0.0.5:53"}, - }, { - name: "specified_three", - in: "c.b.a.x.", - want: []string{"0.0.0.1:53"}, - }, { - name: "specified_four", - in: "d.c.b.a.x.", - want: []string{"0.0.0.1:53"}, - }, { - name: "unspecified_wildcard", - in: "x.z.", - want: []string{"0.0.0.1:53"}, - }, { - name: "unspecified_wildcard_sub", - in: "a.x.z.", - want: []string{"0.0.0.6:53"}, - }} - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ups := uconf.getUpstreamsForDomain(tc.in) - assertUpstreamsForDomain(t, ups, tc.want) - }) - } -} - -func TestGetUpstreamsForDomain_sub_wildcards(t *testing.T) { - conf := []string{ - "0.0.0.1", - "[/a.x/]0.0.0.2", - "[/*.a.x/]0.0.0.3", - "[/*.b.a.x/]0.0.0.5", - } - - uconf, err := ParseUpstreamsConfig(conf, nil) - require.NoError(t, err) - - testCases := []struct { - name string - in string - want []string - }{{ - name: "specified", - in: "a.x.", - want: []string{"0.0.0.2:53"}, - }, { - name: "wildcard", - in: "c.a.x.", - want: []string{"0.0.0.3:53"}, - }, { - name: "sub_spec_ignore", - in: "b.a.x.", - want: []string{"0.0.0.3:53"}, - }, { - name: "sub_spec_wildcard", - in: "d.b.a.x.", - want: []string{"0.0.0.5:53"}, - }} - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ups := uconf.getUpstreamsForDomain(tc.in) - assertUpstreamsForDomain(t, ups, tc.want) - }) - } -} - -func TestGetUpstreamsForDomain_default_wildcards(t *testing.T) { - conf := []string{ - "127.0.0.1:5301", - "[/example.org/]127.0.0.1:5302", - "[/*.example.org/]127.0.0.1:5303", - "[/www.example.org/]127.0.0.1:5304", - "[/*.www.example.org/]#", - } - - uconf, err := ParseUpstreamsConfig(conf, nil) - require.NoError(t, err) - - testCases := []struct { - name string - in string - want []string - }{{ - name: "domain", - in: "example.org.", - want: []string{"127.0.0.1:5302"}, - }, { - name: "sub_wildcard", - in: "sub.example.org.", - want: []string{"127.0.0.1:5303"}, - }, { - name: "spec_sub", - in: "www.example.org.", - want: []string{"127.0.0.1:5304"}, - }, { - name: "def_wildcard", - in: "abc.www.example.org.", - want: []string{"127.0.0.1:5301"}, - }} - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ups := uconf.getUpstreamsForDomain(tc.in) - assertUpstreamsForDomain(t, ups, tc.want) - }) - } -} - -// upsSink is the typed sink variable for the result of benchmarked function. -var upsSink []upstream.Upstream - -func BenchmarkGetUpstreamsForDomain(b *testing.B) { - upstreams := []string{ - "[/google.com/local/]4.3.2.1", - "[/www.google.com//]1.2.3.4", - "[/maps.google.com/]#", - "[/www.google.com/]tls://1.1.1.1", - } - - config, _ := ParseUpstreamsConfig( - upstreams, - &upstream.Options{ - InsecureSkipVerify: false, - Bootstrap: nil, - Timeout: 1 * time.Second, - }, - ) - - domains := []string{ - "www.google.com.", - "www2.google.com.", - "internal.local.", - "google.", - "maps.google.com.", - } - - l := len(domains) - for i := range b.N { - upsSink = config.getUpstreamsForDomain(domains[i%l]) - } -} - -// assertUpstreamsForDomain checks the addresses of the specified domain -// upstreams and their number. -func assertUpstreamsForDomain(tb testing.TB, ups []upstream.Upstream, want []string) { - tb.Helper() - - require.Len(tb, ups, len(want)) - for i, up := range ups { - assert.Equalf(tb, want[i], up.Address(), "bad upstream at index %d", i) - } -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnsproxy-0.70.0/upstream/doh.go new/dnsproxy-0.71.0/upstream/doh.go --- old/dnsproxy-0.70.0/upstream/doh.go 2024-04-18 14:44:55.000000000 +0200 +++ new/dnsproxy-0.71.0/upstream/doh.go 2024-04-26 13:31:22.000000000 +0200 @@ -555,7 +555,7 @@ }, DisableCompression: true, TLSClientConfig: tlsConfig, - QuicConfig: p.getQUICConfig(), + QUICConfig: p.getQUICConfig(), } return &http3Transport{baseTransport: rt}, nil ++++++ dnsproxy.obsinfo ++++++ --- /var/tmp/diff_new_pack.erJnnG/_old 2024-04-29 09:07:58.885553017 +0200 +++ /var/tmp/diff_new_pack.erJnnG/_new 2024-04-29 09:07:58.885553017 +0200 @@ -1,5 +1,5 @@ name: dnsproxy -version: 0.70.0 -mtime: 1713444295 -commit: 7d832999a812b3f237e1b0abd35c87ef559d35a4 +version: 0.71.0 +mtime: 1714131082 +commit: e35720fca466dd5b5f0110eef15cf89b4040f8f1 ++++++ vendor.tar.zstd ++++++ Binary files /var/tmp/diff_new_pack.erJnnG/_old and /var/tmp/diff_new_pack.erJnnG/_new differ
