From 2c8032ce0feaeba785ca508ae9a0820c4e2b99bb Mon Sep 17 00:00:00 2001 From: denis-tingajkin Date: Mon, 13 Apr 2020 23:50:37 +0700 Subject: [PATCH] fix goroutines leak Signed-off-by: denis-tingajkin --- .github/workflows/ci.yaml | 24 ++++++++++++------------ client.go | 12 +++++++++--- coredns/go.sum | 11 +++++++++++ domain_test.go | 2 +- fanout.go | 3 ++- fanout_test.go | 12 +++++++++++- go.mod | 3 +++ go.sum | 18 ++++++++++++++++++ setup.go | 2 +- transport.go | 38 ++++++++++++++++++++++++++++++++------ 10 files changed, 100 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a00cdf5..ce49a04 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code into the Go module directory - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Setup Python uses: actions/setup-python@v1 - name: Install yamllint @@ -18,14 +18,14 @@ jobs: name: shellcheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: shellcheck - uses: azohra/shell-linter@v0.2.0 + uses: fkautz/shell-linter@v1.0.1 build: name: build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - uses: actions/setup-go@v1 with: go-version: 1.13.4 @@ -35,7 +35,7 @@ jobs: name: test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - uses: actions/setup-go@v1 with: go-version: 1.13.4 @@ -53,7 +53,7 @@ jobs: GOLANGCI_LINT_CONTAINER: golangci/golangci-lint:v1.23.2 steps: - name: Check out code into the Go module directory - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Pull golangci-lint docker container run: docker pull ${GOLANGCI_LINT_CONTAINER} - name: Run golangci-lint @@ -65,7 +65,7 @@ jobs: TAG: test ORG: networkservicemesh steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - uses: actions/setup-go@v1 with: go-version: 1.13.4 @@ -82,7 +82,7 @@ jobs: name: exclude fmt.Errorf runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Exclude fmt.Errorf run: | if grep -r --include=*.go fmt.Errorf . ; then @@ -94,7 +94,7 @@ jobs: name: Restrict dependencies on github.com/networkservicemesh/* runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Restrict dependencies on github.com/networkservicemesh/* run: | for i in $(grep github.com/networkservicemesh/ go.mod |grep -v '^module' | sed 's;.*\(github.com\/networkservicemesh\/[a-zA-z\/]*\).*;\1;g' | sort -u);do @@ -108,7 +108,7 @@ jobs: name: check go.mod and go.sum runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - uses: actions/setup-go@v1 with: go-version: 1.13.4 @@ -121,7 +121,7 @@ jobs: name: license header check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - uses: actions/setup-go@v1 with: go-version: 1.13.4 @@ -136,7 +136,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the code - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Exclude replace in go.mod run: | grep ^replace go.mod || exit 0 diff --git a/client.go b/client.go index 682a394..5f29627 100644 --- a/client.go +++ b/client.go @@ -17,6 +17,7 @@ package fanout import ( + "context" "crypto/tls" "fmt" "time" @@ -27,7 +28,7 @@ import ( // Client represents the proxy for remote DNS server type Client interface { - Request(*request.Request) (*dns.Msg, error) + Request(context.Context, *request.Request) (*dns.Msg, error) Endpoint() string SetTLSConfig(*tls.Config) } @@ -62,9 +63,10 @@ func (c *client) Endpoint() string { } // Request sends request to DNS server -func (c *client) Request(r *request.Request) (*dns.Msg, error) { +func (c *client) Request(ctx context.Context, r *request.Request) (*dns.Msg, error) { start := time.Now() - conn, err := c.transport.Dial(c.net) + + conn, err := c.transport.Dial(ctx, c.net) if err != nil { return nil, err } @@ -79,6 +81,10 @@ func (c *client) Request(r *request.Request) (*dns.Msg, error) { } logErrIfNotNil(conn.SetReadDeadline(time.Now().Add(readTimeout))) var ret *dns.Msg + go func() { + <-ctx.Done() + _ = conn.Close() + }() for { ret, err = conn.ReadMsg() if err != nil { diff --git a/coredns/go.sum b/coredns/go.sum index 576e806..e67589b 100644 --- a/coredns/go.sum +++ b/coredns/go.sum @@ -352,6 +352,7 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.5.0-alpha.5.0.20190917205325-a14579fbfb1a/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -359,6 +360,7 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -383,8 +385,11 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -410,6 +415,7 @@ golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -471,7 +477,12 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200413015812-1f08ef6002a8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +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-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/domain_test.go b/domain_test.go index 8f70a8a..19c1bd7 100644 --- a/domain_test.go +++ b/domain_test.go @@ -67,7 +67,7 @@ func TestDomain_ContainsShouldWorkFast(t *testing.T) { for i := 0; i < 10000; i++ { require.True(t, d.Contains(samples[i])) } - require.True(t, time.Since(start) < time.Second/5) + require.True(t, time.Since(start) < time.Second/4) } func TestDomainFewEntries(t *testing.T) { diff --git a/fanout.go b/fanout.go index 2d50b69..b8081e5 100644 --- a/fanout.go +++ b/fanout.go @@ -76,6 +76,7 @@ func (f *Fanout) ServeDNS(ctx context.Context, w dns.ResponseWriter, m *dns.Msg) defer cancel() clientCount := len(f.clients) workerChannel := make(chan Client, f.workerCount) + defer close(workerChannel) responseCh := make(chan *response, clientCount) go func() { for i := 0; i < clientCount; i++ { @@ -148,7 +149,7 @@ func (f *Fanout) processClient(ctx context.Context, c Client, r *request.Request if ctx.Err() != nil { return &response{client: c, response: nil, start: start, err: ctx.Err()} } - msg, err := c.Request(r) + msg, err := c.Request(ctx, r) if err == nil { return &response{client: c, response: msg, start: start, err: err} } diff --git a/fanout_test.go b/fanout_test.go index 7fab3ff..9f8a927 100644 --- a/fanout_test.go +++ b/fanout_test.go @@ -29,6 +29,7 @@ import ( "time" "github.com/stretchr/testify/require" + "go.uber.org/goleak" "github.com/caddyserver/caddy" "github.com/coredns/coredns/plugin/pkg/dnstest" @@ -131,6 +132,7 @@ func TestFanout_ExceptFile(t *testing.T) { } func (t *fanoutTestSuite) TestConfigFromCorefile() { + defer goleak.VerifyNone(t.T()) s := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { ret := new(dns.Msg) ret.SetReply(r) @@ -160,6 +162,7 @@ func (t *fanoutTestSuite) TestConfigFromCorefile() { } func (t *fanoutTestSuite) TestWorkerCountLessThenServers() { + defer goleak.VerifyNone(t.T()) const expected = 1 answerCount := 0 var mutex sync.Mutex @@ -191,6 +194,7 @@ func (t *fanoutTestSuite) TestWorkerCountLessThenServers() { logErrIfNotNil(w.WriteMsg(&msg)) } }) + defer correctServer.close() f.addClient(NewClient(correctServer.addr, t.network)) f.workerCount = 1 @@ -205,6 +209,7 @@ func (t *fanoutTestSuite) TestWorkerCountLessThenServers() { t.Equal(answerCount, expected) } func (t *fanoutTestSuite) TestTwoServersUnsuccessfulResponse() { + defer goleak.VerifyNone(t.T()) rcode := 1 rcodeMutex := sync.Mutex{} s1 := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { @@ -249,11 +254,13 @@ func (t *fanoutTestSuite) TestTwoServersUnsuccessfulResponse() { } func (t *fanoutTestSuite) TestCanReturnUnsuccessfulRepose() { + defer goleak.VerifyNone(t.T()) s := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { msg := nxdomainMsg() msg.SetRcode(r, msg.Rcode) logErrIfNotNil(w.WriteMsg(msg)) }) + defer s.close() f := New() f.net = t.network f.from = "." @@ -269,6 +276,7 @@ func (t *fanoutTestSuite) TestCanReturnUnsuccessfulRepose() { } func (t *fanoutTestSuite) TestBusyServer() { + defer goleak.VerifyNone(t.T()) var requestNum, answerCount int32 totalRequestNum := int32(5) s := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { @@ -284,6 +292,7 @@ func (t *fanoutTestSuite) TestBusyServer() { } atomic.AddInt32(&requestNum, 1) }) + defer s.close() c := NewClient(s.addr, t.network) f := New() f.net = t.network @@ -300,6 +309,7 @@ func (t *fanoutTestSuite) TestBusyServer() { } func (t *fanoutTestSuite) TestTwoServers() { + defer goleak.VerifyNone(t.T()) const expected = 1 var mutex sync.Mutex answerCount1 := 0 @@ -316,6 +326,7 @@ func (t *fanoutTestSuite) TestTwoServers() { logErrIfNotNil(w.WriteMsg(&msg)) } }) + defer s1.close() s2 := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { if r.Question[0].Name == "example2." { msg := dns.Msg{ @@ -328,7 +339,6 @@ func (t *fanoutTestSuite) TestTwoServers() { logErrIfNotNil(w.WriteMsg(&msg)) } }) - defer s1.close() defer s2.close() c1 := NewClient(s1.addr, t.network) diff --git a/go.mod b/go.mod index 508084b..2b2b643 100644 --- a/go.mod +++ b/go.mod @@ -10,4 +10,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.5.0 github.com/stretchr/testify v1.5.1 + go.uber.org/goleak v1.0.0 + golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect + golang.org/x/tools v0.0.0-20200413015812-1f08ef6002a8 // indirect ) diff --git a/go.sum b/go.sum index 41e47b0..18fdd7a 100644 --- a/go.sum +++ b/go.sum @@ -354,6 +354,7 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.5.0-alpha.5.0.20190917205325-a14579fbfb1a/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -361,6 +362,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= +go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -385,8 +388,14 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -412,6 +421,8 @@ golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -473,7 +484,14 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200413015812-1f08ef6002a8 h1:1TnYi6m8UoNpEKS1wxgR8GcHPe2YDgYoDjAedVuX+Q0= +golang.org/x/tools v0.0.0-20200413015812-1f08ef6002a8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +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-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/setup.go b/setup.go index c912f63..0a073f2 100644 --- a/setup.go +++ b/setup.go @@ -249,7 +249,7 @@ func parseProtocol(f *Fanout, c *caddyfile.Dispenser) error { return c.ArgErr() } net := strings.ToLower(c.Val()) - if net != tcp && net != "udp" && net != tcptlc { + if net != tcp && net != udp && net != tcptlc { return errors.New("unknown network protocol") } f.net = net diff --git a/transport.go b/transport.go index f1f97c4..3fb808a 100644 --- a/transport.go +++ b/transport.go @@ -17,14 +17,16 @@ package fanout import ( + "context" "crypto/tls" + "net" "github.com/miekg/dns" ) // Transport represent a solution to connect to remote DNS endpoint with specific network type Transport interface { - Dial(net string) (*dns.Conn, error) + Dial(ctx context.Context, net string) (*dns.Conn, error) SetTLSConfig(*tls.Config) } @@ -46,12 +48,36 @@ func (t *transportImpl) SetTLSConfig(c *tls.Config) { } // Dial dials the address configured in transportImpl, potentially reusing a connection or creating a new one. -func (t *transportImpl) Dial(net string) (*dns.Conn, error) { +func (t *transportImpl) Dial(ctx context.Context, network string) (*dns.Conn, error) { if t.tlsConfig != nil { - net = tcptlc + network = tcptlc } - if net == tcptlc { - return dns.DialTimeoutWithTLS("tcp", t.addr, t.tlsConfig, defaultTimeout) + if network == tcptlc { + return t.dial(ctx, &dns.Client{Net: network, Dialer: &net.Dialer{Timeout: maxTimeout}, TLSConfig: t.tlsConfig}) } - return dns.DialTimeout(net, t.addr, defaultTimeout) + return t.dial(ctx, &dns.Client{Net: network, Dialer: &net.Dialer{Timeout: maxTimeout}}) +} + +func (t *transportImpl) dial(ctx context.Context, c *dns.Client) (*dns.Conn, error) { + var d net.Dialer + if c.Dialer == nil { + d = net.Dialer{Timeout: maxTimeout} + } else { + d = *c.Dialer + } + network := c.Net + if network == "" { + network = "udp" + } + var conn = new(dns.Conn) + var err error + if network == tcptlc { + conn.Conn, err = tls.DialWithDialer(&d, network, t.addr, c.TLSConfig) + } else { + conn.Conn, err = d.DialContext(ctx, network, t.addr) + } + if err != nil { + return nil, err + } + return conn, nil }