Skip to content

Commit

Permalink
Merge branch 'master' into AG-23599-use-hostsfile-vol.2
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Oct 5, 2023
2 parents 34750a6 + 60d2174 commit 718aee8
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 80 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ module github.com/AdguardTeam/dnsproxy
go 1.20

require (
github.com/AdguardTeam/golibs v0.16.2
github.com/AdguardTeam/golibs v0.17.0
github.com/ameshkov/dnscrypt/v2 v2.2.7
github.com/ameshkov/dnsstamps v1.0.3
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0
github.com/bluele/gcache v0.0.2
github.com/jessevdk/go-flags v1.5.0
github.com/miekg/dns v1.1.56
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/quic-go/quic-go v0.38.1
github.com/quic-go/quic-go v0.39.0
github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
golang.org/x/net v0.15.0
Expand All @@ -24,14 +24,14 @@ require (
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/onsi/ginkgo/v2 v2.12.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
go.uber.org/mock v0.3.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
Expand Down
35 changes: 6 additions & 29 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/AdguardTeam/golibs v0.16.2 h1:54286tqaGZl3L13EV1PbaMnGqJkFJdaVtqFpDNEKZi8=
github.com/AdguardTeam/golibs v0.16.2/go.mod h1:DKhCIXHcUYtBhU8ibTLKh1paUL96n5zhQBlx763sj+U=
github.com/AdguardTeam/golibs v0.17.0 h1:oPp2+2kV41qH45AIFbAlHFTPQOQ6JbF+JemjeECFn1g=
github.com/AdguardTeam/golibs v0.17.0/go.mod h1:DKhCIXHcUYtBhU8ibTLKh1paUL96n5zhQBlx763sj+U=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
Expand All @@ -19,8 +19,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 h1:gpptm606MZYGaMHMsB4Srmb6EbW/IVHnt04rcMXnkBQ=
Expand All @@ -46,51 +44,30 @@ 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/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE=
github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4=
github.com/quic-go/quic-go v0.39.0 h1:AgP40iThFMY0bj8jGxROhw3S0FMGa8ryqsmi9tBH3So=
github.com/quic-go/quic-go v0.39.0/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
Expand Down
16 changes: 13 additions & 3 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,18 +458,28 @@ func (p *Proxy) needsLocalUpstream(req *dns.Msg) (ok bool) {
// firstly considers custom upstreams if those aren't empty and then the
// configured ones. The returned slice may be empty or nil.
func (p *Proxy) selectUpstreams(d *DNSContext) (upstreams []upstream.Upstream) {
host := d.Req.Question[0].Name
q := d.Req.Question[0]
host := q.Name
qtype := q.Qtype

if !p.needsLocalUpstream(d.Req) {
// TODO(e.burkov): Use the same logic for private upstreams as well,
// when those start supporting non-PTR requests.
getUpstreams := (*UpstreamConfig).getUpstreamsForDomain
if qtype == dns.TypeDS {
getUpstreams = (*UpstreamConfig).getUpstreamsForDS
}

if custom := d.CustomUpstreamConfig; custom != nil {
// Try to use custom.
upstreams = custom.getUpstreamsForDomain(host)
upstreams = getUpstreams(custom, host)
if len(upstreams) > 0 {
return upstreams
}
}

// Use configured.
return p.UpstreamConfig.getUpstreamsForDomain(host)
return getUpstreams(p.UpstreamConfig, host)
}

// Use private upstreams.
Expand Down
35 changes: 24 additions & 11 deletions proxy/upstreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,6 @@ func (uc *UpstreamConfig) getUpstreamsForDomain(host string) (ups []upstream.Ups
return uc.Upstreams
}

var ok bool

dotsCount := strings.Count(host, ".")
if dotsCount < 2 {
host = UnqualifiedNames
Expand All @@ -223,21 +221,36 @@ func (uc *UpstreamConfig) getUpstreamsForDomain(host string) (ups []upstream.Ups
}
}

for i := 1; i <= dotsCount; i++ {
h := strings.SplitAfterN(host, ".", i)
name := h[i-1]

ups, ok = uc.lookupUpstreams(name)
if !ok {
continue
for host != "" {
var ok bool
if ups, ok = uc.lookupUpstreams(host); ok {
return ups
}

return ups
_, host, _ = strings.Cut(host, ".")
}

return uc.Upstreams
}

// getUpstreamsForDS is like [getUpstreamsForDomain], but intended for DS
// queries only, so that it matches the host 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
// key in the child zone used to verify the RRSIGs in that zone. All DS RRsets
// 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 {
return uc.Upstreams
}

return uc.getUpstreamsForDomain(host)
}

// lookupSubdomainExclusion returns upstreams for the host from subdomain
// exclusions list.
func (uc *UpstreamConfig) lookupSubdomainExclusion(host string) (u []upstream.Upstream) {
Expand Down Expand Up @@ -266,7 +279,7 @@ func (uc *UpstreamConfig) lookupUpstreams(name string) (ups []upstream.Upstream,

if len(ups) == 0 {
// The domain has been excluded from reserved upstreams querying.
return uc.Upstreams, true
ups = uc.Upstreams
}

return ups, true
Expand Down
137 changes: 114 additions & 23 deletions proxy/upstreams_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestGetUpstreamsForDomain(t *testing.T) {
func TestUpstreamConfig_GetUpstreamsForDomain(t *testing.T) {
upstreams := []string{
"[/google.com/local/]4.3.2.1",
"[/www.google.com//]1.2.3.4",
Expand All @@ -28,12 +28,95 @@ func TestGetUpstreamsForDomain(t *testing.T) {
)
require.NoError(t, err)

assertUpstreamsForDomain(t, config, "www.google.com.", []string{"1.2.3.4:53", "tls://1.1.1.1:853"})
assertUpstreamsForDomain(t, config, "www2.google.com.", []string{"4.3.2.1:53"})
assertUpstreamsForDomain(t, config, "internal.local.", []string{"4.3.2.1:53"})
assertUpstreamsForDomain(t, config, "google.", []string{"1.2.3.4:53"})
assertUpstreamsForDomain(t, config, "_acme-challenge.example.org.", []string{})
assertUpstreamsForDomain(t, config, "maps.google.com.", []string{})
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{},
}}

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,
Bootstrap: []string{},
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) {
Expand Down Expand Up @@ -157,7 +240,8 @@ func TestGetUpstreamsForDomain_wildcards(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
assertUpstreamsForDomain(t, uconf, tc.in, tc.want)
ups := uconf.getUpstreamsForDomain(tc.in)
assertUpstreamsForDomain(t, ups, tc.want)
})
}
}
Expand Down Expand Up @@ -197,7 +281,8 @@ func TestGetUpstreamsForDomain_sub_wildcards(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
assertUpstreamsForDomain(t, uconf, tc.in, tc.want)
ups := uconf.getUpstreamsForDomain(tc.in)
assertUpstreamsForDomain(t, ups, tc.want)
})
}
}
Expand Down Expand Up @@ -238,11 +323,15 @@ func TestGetUpstreamsForDomain_default_wildcards(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
assertUpstreamsForDomain(t, uconf, tc.in, tc.want)
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",
Expand All @@ -260,24 +349,26 @@ func BenchmarkGetUpstreamsForDomain(b *testing.B) {
},
)

for i := 0; i < b.N; i++ {
assertUpstreamsForDomain(b, config, "www.google.com.", []string{"1.2.3.4:53", "tls://1.1.1.1:853"})
assertUpstreamsForDomain(b, config, "www2.google.com.", []string{"4.3.2.1:53"})
assertUpstreamsForDomain(b, config, "internal.local.", []string{"4.3.2.1:53"})
assertUpstreamsForDomain(b, config, "google.", []string{"1.2.3.4:53"})
assertUpstreamsForDomain(b, config, "maps.google.com.", []string{})
domains := []string{
"www.google.com.",
"www2.google.com.",
"internal.local.",
"google.",
"maps.google.com.",
}

for i, l := 0, len(domains); i < b.N; i++ {
upsSink = config.getUpstreamsForDomain(domains[i%l])
}
}

// assertUpstreamsForDomain checks the addresses of the specified domain
// upstreams and their number.
func assertUpstreamsForDomain(t testing.TB, config *UpstreamConfig, domain string, address []string) {
t.Helper()

u := config.getUpstreamsForDomain(domain)
require.Len(t, u, len(address))
func assertUpstreamsForDomain(tb testing.TB, ups []upstream.Upstream, want []string) {
tb.Helper()

for i, up := range u {
assert.Equalf(t, address[i], up.Address(), "bad upstream at index %d", i)
require.Len(tb, ups, len(want))
for i, up := range ups {
assert.Equalf(tb, want[i], up.Address(), "bad upstream at index %d", i)
}
}
Loading

0 comments on commit 718aee8

Please sign in to comment.