mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Merge pull request #468 in YUNIONIO/onecloud from ~TANGBIN/onecloud:bugfix/tb-fix-make-regiondns-error to release/2.3.0
* commit '6599ddc53b9a0ddb46c85ce08238c6e90c3e4b03': rm transitive dependents fix depends fix region-dns build error
This commit is contained in:
Generated
+16
-19
@@ -113,12 +113,11 @@
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e64acfe8cda1955db545ede8e863c54d69f1ac6cd058df4349be4040320840fd"
|
||||
digest = "1:eee9386329f4fcdf8d6c0def0c9771b634bdd5ba460d888aa98c17d59b37a76c"
|
||||
name = "github.com/apache/thrift"
|
||||
packages = ["lib/go/thrift"]
|
||||
pruneopts = "UT"
|
||||
revision = "327ebb6c2b6df8bf075da02ef45a2a034e9b79ba"
|
||||
version = "0.11.0"
|
||||
revision = "e59b73d3c2bf1c328ccb78e683c0462fa1a473c7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:55bf2a4da68caa693d660683e53bab3e651a940cd46354b997ab68bec7920e23"
|
||||
@@ -190,7 +189,7 @@
|
||||
version = "v0.2.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1c45e98df3726b24a0cc200f5ed182e5eefbe6a8cf2927f9d4335151aa190d15"
|
||||
digest = "1:40098afbdd06a76dee4b6bcb85a22fed81ac9d2ebaf775c91e558c80f57aaff1"
|
||||
name = "github.com/coredns/coredns"
|
||||
packages = [
|
||||
"core/dnsserver",
|
||||
@@ -232,7 +231,6 @@
|
||||
"plugin/pkg/response",
|
||||
"plugin/pkg/tls",
|
||||
"plugin/pkg/trace",
|
||||
"plugin/pkg/transport",
|
||||
"plugin/pkg/uniq",
|
||||
"plugin/pkg/up",
|
||||
"plugin/pkg/upstream",
|
||||
@@ -244,8 +242,8 @@
|
||||
"request",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "756749c5cad4cd40453b82f70592bc19bb9ccb15"
|
||||
version = "v1.2.6"
|
||||
revision = "2e322f6e8a54f18c6aef9c25a7c432c291a3d9f7"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
||||
@@ -806,16 +804,15 @@
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:26663fafdea73a38075b07e8e9d82fc0056379d2be8bb4e13899e8fda7c7dd23"
|
||||
digest = "1:d14a5f4bfecf017cb780bdde1b6483e5deb87e12c332544d2c430eda58734bcb"
|
||||
name = "github.com/prometheus/client_golang"
|
||||
packages = [
|
||||
"prometheus",
|
||||
"prometheus/internal",
|
||||
"prometheus/promhttp",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "abad2d1bd44235a26707c172eab6bca5bf2dbad3"
|
||||
version = "v0.9.1"
|
||||
revision = "c5b7fccd204277076155f10851dad72b76a49317"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -1292,14 +1289,6 @@
|
||||
revision = "1638f8970cefaa404ff3a62950f88b08292b2696"
|
||||
version = "v9.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7719608fe0b52a4ece56c2dde37bedd95b938677d1ab0f84b8a7852e4c59f849"
|
||||
name = "sigs.k8s.io/yaml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:356a33d2d627cbb232a1d71cc42051fbac0e5e6a1717679f110054baa02472e5"
|
||||
name = "k8s.io/kubernetes"
|
||||
@@ -1311,6 +1300,14 @@
|
||||
revision = "17c77c7898218073f14c8d573582e8d2313dc740"
|
||||
version = "v1.12.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7719608fe0b52a4ece56c2dde37bedd95b938677d1ab0f84b8a7852e4c59f849"
|
||||
name = "sigs.k8s.io/yaml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:54554b3c72f4fcbd3c27c5137f9acd9d153d7e7150d77cd509af50c75fcb41b9"
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/coredns/coredns"
|
||||
version = "1.2.6"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/fatih/color"
|
||||
|
||||
@@ -136,11 +136,10 @@ func init() {
|
||||
}
|
||||
|
||||
shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *qcloud.SRegion, args *InstanceRebuildRootOptions) error {
|
||||
diskID, err := cli.ReplaceSystemDisk(args.ID, args.Image, args.Password, args.Keypair, args.Size)
|
||||
err := cli.ReplaceSystemDisk(args.ID, args.Image, args.Password, args.Keypair, args.Size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("New diskID is %s", diskID)
|
||||
return nil
|
||||
})
|
||||
|
||||
|
||||
+3
-2
@@ -21,6 +21,7 @@ package thrift
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -457,8 +458,8 @@ func (p *TBinaryProtocol) ReadBinary() ([]byte, error) {
|
||||
return buf, NewTProtocolException(err)
|
||||
}
|
||||
|
||||
func (p *TBinaryProtocol) Flush() (err error) {
|
||||
return NewTProtocolException(p.trans.Flush())
|
||||
func (p *TBinaryProtocol) Flush(ctx context.Context) (err error) {
|
||||
return NewTProtocolException(p.trans.Flush(ctx))
|
||||
}
|
||||
|
||||
func (p *TBinaryProtocol) Skip(fieldType TType) (err error) {
|
||||
|
||||
+3
-2
@@ -21,6 +21,7 @@ package thrift
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
)
|
||||
|
||||
type TBufferedTransportFactory struct {
|
||||
@@ -78,12 +79,12 @@ func (p *TBufferedTransport) Write(b []byte) (int, error) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (p *TBufferedTransport) Flush() error {
|
||||
func (p *TBufferedTransport) Flush(ctx context.Context) error {
|
||||
if err := p.ReadWriter.Flush(); err != nil {
|
||||
p.ReadWriter.Writer.Reset(p.tp)
|
||||
return err
|
||||
}
|
||||
return p.tp.Flush()
|
||||
return p.tp.Flush(ctx)
|
||||
}
|
||||
|
||||
func (p *TBufferedTransport) RemainingBytes() (num_bytes uint64) {
|
||||
|
||||
+12
-5
@@ -1,6 +1,13 @@
|
||||
package thrift
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type TClient interface {
|
||||
Call(ctx context.Context, method string, args, result TStruct) error
|
||||
}
|
||||
|
||||
type TStandardClient struct {
|
||||
seqId int32
|
||||
@@ -16,7 +23,7 @@ func NewTStandardClient(inputProtocol, outputProtocol TProtocol) *TStandardClien
|
||||
}
|
||||
}
|
||||
|
||||
func (p *TStandardClient) Send(oprot TProtocol, seqId int32, method string, args TStruct) error {
|
||||
func (p *TStandardClient) Send(ctx context.Context, oprot TProtocol, seqId int32, method string, args TStruct) error {
|
||||
if err := oprot.WriteMessageBegin(method, CALL, seqId); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -26,7 +33,7 @@ func (p *TStandardClient) Send(oprot TProtocol, seqId int32, method string, args
|
||||
if err := oprot.WriteMessageEnd(); err != nil {
|
||||
return err
|
||||
}
|
||||
return oprot.Flush()
|
||||
return oprot.Flush(ctx)
|
||||
}
|
||||
|
||||
func (p *TStandardClient) Recv(iprot TProtocol, seqId int32, method string, result TStruct) error {
|
||||
@@ -61,11 +68,11 @@ func (p *TStandardClient) Recv(iprot TProtocol, seqId int32, method string, resu
|
||||
return iprot.ReadMessageEnd()
|
||||
}
|
||||
|
||||
func (p *TStandardClient) call(method string, args, result TStruct) error {
|
||||
func (p *TStandardClient) Call(ctx context.Context, method string, args, result TStruct) error {
|
||||
p.seqId++
|
||||
seqId := p.seqId
|
||||
|
||||
if err := p.Send(p.oprot, seqId, method, args); err != nil {
|
||||
if err := p.Send(ctx, p.oprot, seqId, method, args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// +build go1.7
|
||||
|
||||
package thrift
|
||||
|
||||
import "context"
|
||||
|
||||
type TClient interface {
|
||||
Call(ctx context.Context, method string, args, result TStruct) error
|
||||
}
|
||||
|
||||
func (p *TStandardClient) Call(ctx context.Context, method string, args, result TStruct) error {
|
||||
return p.call(method, args, result)
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// +build !go1.7
|
||||
|
||||
package thrift
|
||||
|
||||
import "golang.org/x/net/context"
|
||||
|
||||
type TClient interface {
|
||||
Call(ctx context.Context, method string, args, result TStruct) error
|
||||
}
|
||||
|
||||
func (p *TStandardClient) Call(ctx context.Context, method string, args, result TStruct) error {
|
||||
return p.call(method, args, result)
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
// +build go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package thrift
|
||||
|
||||
import "context"
|
||||
|
||||
type mockProcessor struct {
|
||||
ProcessFunc func(in, out TProtocol) (bool, TException)
|
||||
}
|
||||
|
||||
func (m *mockProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
|
||||
return m.ProcessFunc(in, out)
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
// +build !go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package thrift
|
||||
|
||||
import "golang.org/x/net/context"
|
||||
|
||||
type mockProcessor struct {
|
||||
ProcessFunc func(in, out TProtocol) (bool, TException)
|
||||
}
|
||||
|
||||
func (m *mockProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
|
||||
return m.ProcessFunc(in, out)
|
||||
}
|
||||
+4
-3
@@ -20,6 +20,7 @@
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -599,8 +600,8 @@ func (p *TCompactProtocol) ReadBinary() (value []byte, err error) {
|
||||
return buf, NewTProtocolException(e)
|
||||
}
|
||||
|
||||
func (p *TCompactProtocol) Flush() (err error) {
|
||||
return NewTProtocolException(p.trans.Flush())
|
||||
func (p *TCompactProtocol) Flush(ctx context.Context) (err error) {
|
||||
return NewTProtocolException(p.trans.Flush(ctx))
|
||||
}
|
||||
|
||||
func (p *TCompactProtocol) Skip(fieldType TType) (err error) {
|
||||
@@ -806,7 +807,7 @@ func (p *TCompactProtocol) getTType(t tCompactType) (TType, error) {
|
||||
case COMPACT_STRUCT:
|
||||
return STRUCT, nil
|
||||
}
|
||||
return STOP, TException(fmt.Errorf("don't know what type: %s", t&0x0f))
|
||||
return STOP, TException(fmt.Errorf("don't know what type: %v", t&0x0f))
|
||||
}
|
||||
|
||||
// Given a TType value, find the appropriate TCompactProtocol.Types constant.
|
||||
|
||||
Generated
Vendored
-2
@@ -1,5 +1,3 @@
|
||||
// +build go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
+3
-2
@@ -20,6 +20,7 @@
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
)
|
||||
|
||||
@@ -258,8 +259,8 @@ func (tdp *TDebugProtocol) Skip(fieldType TType) (err error) {
|
||||
log.Printf("%sSkip(fieldType=%#v) (err=%#v)", tdp.LogPrefix, fieldType, err)
|
||||
return
|
||||
}
|
||||
func (tdp *TDebugProtocol) Flush() (err error) {
|
||||
err = tdp.Delegate.Flush()
|
||||
func (tdp *TDebugProtocol) Flush(ctx context.Context) (err error) {
|
||||
err = tdp.Delegate.Flush(ctx)
|
||||
log.Printf("%sFlush() (err=%#v)", tdp.LogPrefix, err)
|
||||
return
|
||||
}
|
||||
|
||||
+3
-2
@@ -22,6 +22,7 @@ package thrift
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -135,7 +136,7 @@ func (p *TFramedTransport) WriteString(s string) (n int, err error) {
|
||||
return p.buf.WriteString(s)
|
||||
}
|
||||
|
||||
func (p *TFramedTransport) Flush() error {
|
||||
func (p *TFramedTransport) Flush(ctx context.Context) error {
|
||||
size := p.buf.Len()
|
||||
buf := p.buffer[:4]
|
||||
binary.BigEndian.PutUint32(buf, uint32(size))
|
||||
@@ -151,7 +152,7 @@ func (p *TFramedTransport) Flush() error {
|
||||
return NewTTransportExceptionFromError(err)
|
||||
}
|
||||
}
|
||||
err = p.transport.Flush()
|
||||
err = p.transport.Flush(ctx)
|
||||
return NewTTransportExceptionFromError(err)
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -21,6 +21,7 @@ package thrift
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -181,7 +182,7 @@ func (p *THttpClient) WriteString(s string) (n int, err error) {
|
||||
return p.requestBuffer.WriteString(s)
|
||||
}
|
||||
|
||||
func (p *THttpClient) Flush() error {
|
||||
func (p *THttpClient) Flush(ctx context.Context) error {
|
||||
// Close any previous response body to avoid leaking connections.
|
||||
p.closeResponse()
|
||||
|
||||
@@ -190,6 +191,9 @@ func (p *THttpClient) Flush() error {
|
||||
return NewTTransportExceptionFromError(err)
|
||||
}
|
||||
req.Header = p.header
|
||||
if ctx != nil {
|
||||
req = req.WithContext(ctx)
|
||||
}
|
||||
response, err := p.client.Do(req)
|
||||
if err != nil {
|
||||
return NewTTransportExceptionFromError(err)
|
||||
|
||||
+12
@@ -26,6 +26,18 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewThriftHandlerFunc is a function that create a ready to use Apache Thrift Handler function
|
||||
func NewThriftHandlerFunc(processor TProcessor,
|
||||
inPfactory, outPfactory TProtocolFactory) func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
return gz(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Type", "application/x-thrift")
|
||||
|
||||
transport := NewStreamTransport(r.Body, w)
|
||||
processor.Process(r.Context(), inPfactory.GetProtocol(transport), outPfactory.GetProtocol(transport))
|
||||
})
|
||||
}
|
||||
|
||||
// gz transparently compresses the HTTP response if the client supports it.
|
||||
func gz(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
// +build go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// NewThriftHandlerFunc is a function that create a ready to use Apache Thrift Handler function
|
||||
func NewThriftHandlerFunc(processor TProcessor,
|
||||
inPfactory, outPfactory TProtocolFactory) func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
return gz(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Type", "application/x-thrift")
|
||||
|
||||
transport := NewStreamTransport(r.Body, w)
|
||||
processor.Process(r.Context(), inPfactory.GetProtocol(transport), outPfactory.GetProtocol(transport))
|
||||
})
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
// +build !go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// NewThriftHandlerFunc is a function that create a ready to use Apache Thrift Handler function
|
||||
func NewThriftHandlerFunc(processor TProcessor,
|
||||
inPfactory, outPfactory TProtocolFactory) func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
return gz(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Type", "application/x-thrift")
|
||||
|
||||
transport := NewStreamTransport(r.Body, w)
|
||||
processor.Process(context.Background(), inPfactory.GetProtocol(transport), outPfactory.GetProtocol(transport))
|
||||
})
|
||||
}
|
||||
+2
-1
@@ -21,6 +21,7 @@ package thrift
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
@@ -138,7 +139,7 @@ func (p *StreamTransport) Close() error {
|
||||
}
|
||||
|
||||
// Flushes the underlying output stream if not null.
|
||||
func (p *StreamTransport) Flush() error {
|
||||
func (p *StreamTransport) Flush(ctx context.Context) error {
|
||||
if p.Writer == nil {
|
||||
return NewTTransportException(NOT_OPEN, "Cannot flush null outputStream")
|
||||
}
|
||||
|
||||
+3
-2
@@ -20,6 +20,7 @@
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
)
|
||||
@@ -438,10 +439,10 @@ func (p *TJSONProtocol) ReadBinary() ([]byte, error) {
|
||||
return v, p.ParsePostValue()
|
||||
}
|
||||
|
||||
func (p *TJSONProtocol) Flush() (err error) {
|
||||
func (p *TJSONProtocol) Flush(ctx context.Context) (err error) {
|
||||
err = p.writer.Flush()
|
||||
if err == nil {
|
||||
err = p.trans.Flush()
|
||||
err = p.trans.Flush(ctx)
|
||||
}
|
||||
return NewTProtocolException(err)
|
||||
}
|
||||
|
||||
+2
-1
@@ -21,6 +21,7 @@ package thrift
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
)
|
||||
|
||||
// Memory buffer-based implementation of the TTransport interface.
|
||||
@@ -70,7 +71,7 @@ func (p *TMemoryBuffer) Close() error {
|
||||
}
|
||||
|
||||
// Flushing a memory buffer is a no-op
|
||||
func (p *TMemoryBuffer) Flush() error {
|
||||
func (p *TMemoryBuffer) Flush(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+31
@@ -19,6 +19,12 @@
|
||||
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
TMultiplexedProtocol is a protocol-independent concrete decorator
|
||||
that allows a Thrift client to communicate with a multiplexing Thrift server,
|
||||
@@ -122,6 +128,31 @@ func (t *TMultiplexedProcessor) RegisterProcessor(name string, processor TProces
|
||||
t.serviceProcessorMap[name] = processor
|
||||
}
|
||||
|
||||
func (t *TMultiplexedProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
|
||||
name, typeId, seqid, err := in.ReadMessageBegin()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if typeId != CALL && typeId != ONEWAY {
|
||||
return false, fmt.Errorf("Unexpected message type %v", typeId)
|
||||
}
|
||||
//extract the service name
|
||||
v := strings.SplitN(name, MULTIPLEXED_SEPARATOR, 2)
|
||||
if len(v) != 2 {
|
||||
if t.DefaultProcessor != nil {
|
||||
smb := NewStoredMessageProtocol(in, name, typeId, seqid)
|
||||
return t.DefaultProcessor.Process(ctx, smb, out)
|
||||
}
|
||||
return false, fmt.Errorf("Service name not found in message name: %s. Did you forget to use a TMultiplexProtocol in your client?", name)
|
||||
}
|
||||
actualProcessor, ok := t.serviceProcessorMap[v[0]]
|
||||
if !ok {
|
||||
return false, fmt.Errorf("Service name not found: %s. Did you forget to call registerProcessor()?", v[0])
|
||||
}
|
||||
smb := NewStoredMessageProtocol(in, v[1], typeId, seqid)
|
||||
return actualProcessor.Process(ctx, smb, out)
|
||||
}
|
||||
|
||||
//Protocol that use stored message for ReadMessageBegin
|
||||
type storedMessageProtocol struct {
|
||||
TProtocol
|
||||
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
// +build go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (t *TMultiplexedProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
|
||||
name, typeId, seqid, err := in.ReadMessageBegin()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if typeId != CALL && typeId != ONEWAY {
|
||||
return false, fmt.Errorf("Unexpected message type %v", typeId)
|
||||
}
|
||||
//extract the service name
|
||||
v := strings.SplitN(name, MULTIPLEXED_SEPARATOR, 2)
|
||||
if len(v) != 2 {
|
||||
if t.DefaultProcessor != nil {
|
||||
smb := NewStoredMessageProtocol(in, name, typeId, seqid)
|
||||
return t.DefaultProcessor.Process(ctx, smb, out)
|
||||
}
|
||||
return false, fmt.Errorf("Service name not found in message name: %s. Did you forget to use a TMultiplexProtocol in your client?", name)
|
||||
}
|
||||
actualProcessor, ok := t.serviceProcessorMap[v[0]]
|
||||
if !ok {
|
||||
return false, fmt.Errorf("Service name not found: %s. Did you forget to call registerProcessor()?", v[0])
|
||||
}
|
||||
smb := NewStoredMessageProtocol(in, v[1], typeId, seqid)
|
||||
return actualProcessor.Process(ctx, smb, out)
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
// +build !go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (t *TMultiplexedProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
|
||||
name, typeId, seqid, err := in.ReadMessageBegin()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if typeId != CALL && typeId != ONEWAY {
|
||||
return false, fmt.Errorf("Unexpected message type %v", typeId)
|
||||
}
|
||||
//extract the service name
|
||||
v := strings.SplitN(name, MULTIPLEXED_SEPARATOR, 2)
|
||||
if len(v) != 2 {
|
||||
if t.DefaultProcessor != nil {
|
||||
smb := NewStoredMessageProtocol(in, name, typeId, seqid)
|
||||
return t.DefaultProcessor.Process(ctx, smb, out)
|
||||
}
|
||||
return false, fmt.Errorf("Service name not found in message name: %s. Did you forget to use a TMultiplexProtocol in your client?", name)
|
||||
}
|
||||
actualProcessor, ok := t.serviceProcessorMap[v[0]]
|
||||
if !ok {
|
||||
return false, fmt.Errorf("Service name not found: %s. Did you forget to call registerProcessor()?", v[0])
|
||||
}
|
||||
smb := NewStoredMessageProtocol(in, v[1], typeId, seqid)
|
||||
return actualProcessor.Process(ctx, smb, out)
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
// +build !go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package thrift
|
||||
|
||||
import "golang.org/x/net/context"
|
||||
|
||||
var defaultCtx = context.Background()
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
// +build !go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package thrift
|
||||
|
||||
import "golang.org/x/net/context"
|
||||
|
||||
// A processor is a generic object which operates upon an input stream and
|
||||
// writes to some output stream.
|
||||
type TProcessor interface {
|
||||
Process(ctx context.Context, in, out TProtocol) (bool, TException)
|
||||
}
|
||||
|
||||
type TProcessorFunction interface {
|
||||
Process(ctx context.Context, seqId int32, in, out TProtocol) (bool, TException)
|
||||
}
|
||||
+12
@@ -19,6 +19,18 @@
|
||||
|
||||
package thrift
|
||||
|
||||
import "context"
|
||||
|
||||
// A processor is a generic object which operates upon an input stream and
|
||||
// writes to some output stream.
|
||||
type TProcessor interface {
|
||||
Process(ctx context.Context, in, out TProtocol) (bool, TException)
|
||||
}
|
||||
|
||||
type TProcessorFunction interface {
|
||||
Process(ctx context.Context, seqId int32, in, out TProtocol) (bool, TException)
|
||||
}
|
||||
|
||||
// The default processor factory just returns a singleton
|
||||
// instance.
|
||||
type TProcessorFactory interface {
|
||||
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
// +build go1.7
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package thrift
|
||||
|
||||
import "context"
|
||||
|
||||
// A processor is a generic object which operates upon an input stream and
|
||||
// writes to some output stream.
|
||||
type TProcessor interface {
|
||||
Process(ctx context.Context, in, out TProtocol) (bool, TException)
|
||||
}
|
||||
|
||||
type TProcessorFunction interface {
|
||||
Process(ctx context.Context, seqId int32, in, out TProtocol) (bool, TException)
|
||||
}
|
||||
+2
-1
@@ -20,6 +20,7 @@
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
@@ -74,7 +75,7 @@ type TProtocol interface {
|
||||
ReadBinary() (value []byte, err error)
|
||||
|
||||
Skip(fieldType TType) (err error)
|
||||
Flush() (err error)
|
||||
Flush(ctx context.Context) (err error)
|
||||
|
||||
Transport() TTransport
|
||||
}
|
||||
|
||||
+10
-6
@@ -19,6 +19,10 @@
|
||||
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type TSerializer struct {
|
||||
Transport *TMemoryBuffer
|
||||
Protocol TProtocol
|
||||
@@ -38,35 +42,35 @@ func NewTSerializer() *TSerializer {
|
||||
protocol}
|
||||
}
|
||||
|
||||
func (t *TSerializer) WriteString(msg TStruct) (s string, err error) {
|
||||
func (t *TSerializer) WriteString(ctx context.Context, msg TStruct) (s string, err error) {
|
||||
t.Transport.Reset()
|
||||
|
||||
if err = msg.Write(t.Protocol); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = t.Protocol.Flush(); err != nil {
|
||||
if err = t.Protocol.Flush(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
if err = t.Transport.Flush(); err != nil {
|
||||
if err = t.Transport.Flush(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return t.Transport.String(), nil
|
||||
}
|
||||
|
||||
func (t *TSerializer) Write(msg TStruct) (b []byte, err error) {
|
||||
func (t *TSerializer) Write(ctx context.Context, msg TStruct) (b []byte, err error) {
|
||||
t.Transport.Reset()
|
||||
|
||||
if err = msg.Write(t.Protocol); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = t.Protocol.Flush(); err != nil {
|
||||
if err = t.Protocol.Flush(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = t.Transport.Flush(); err != nil {
|
||||
if err = t.Transport.Flush(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -22,6 +22,7 @@ package thrift
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -552,7 +553,7 @@ func (p *TSimpleJSONProtocol) ReadBinary() ([]byte, error) {
|
||||
return v, p.ParsePostValue()
|
||||
}
|
||||
|
||||
func (p *TSimpleJSONProtocol) Flush() (err error) {
|
||||
func (p *TSimpleJSONProtocol) Flush(ctx context.Context) (err error) {
|
||||
return NewTProtocolException(p.writer.Flush())
|
||||
}
|
||||
|
||||
@@ -1064,7 +1065,7 @@ func (p *TSimpleJSONProtocol) ParseListEnd() error {
|
||||
for _, char := range line {
|
||||
switch char {
|
||||
default:
|
||||
e := fmt.Errorf("Expecting end of list \"]\", but found: \"", line, "\"")
|
||||
e := fmt.Errorf("Expecting end of list \"]\", but found: \"%v\"", line)
|
||||
return NewTProtocolExceptionWithType(INVALID_DATA, e)
|
||||
case ' ', '\n', '\r', '\t', rune(JSON_RBRACKET[0]):
|
||||
break
|
||||
|
||||
+26
-14
@@ -125,26 +125,38 @@ func (p *TSimpleServer) Listen() error {
|
||||
return p.serverTransport.Listen()
|
||||
}
|
||||
|
||||
func (p *TSimpleServer) innerAccept() (int32, error) {
|
||||
client, err := p.serverTransport.Accept()
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
closed := atomic.LoadInt32(&p.closed)
|
||||
if closed != 0 {
|
||||
return closed, nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if client != nil {
|
||||
p.wg.Add(1)
|
||||
go func() {
|
||||
defer p.wg.Done()
|
||||
if err := p.processRequests(client); err != nil {
|
||||
log.Println("error processing request:", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (p *TSimpleServer) AcceptLoop() error {
|
||||
for {
|
||||
client, err := p.serverTransport.Accept()
|
||||
p.mu.Lock()
|
||||
if atomic.LoadInt32(&p.closed) != 0 {
|
||||
return nil
|
||||
}
|
||||
closed, err := p.innerAccept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if client != nil {
|
||||
p.wg.Add(1)
|
||||
go func() {
|
||||
defer p.wg.Done()
|
||||
if err := p.processRequests(client); err != nil {
|
||||
log.Println("error processing request:", err)
|
||||
}
|
||||
}()
|
||||
if closed != 0 {
|
||||
return nil
|
||||
}
|
||||
p.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
@@ -148,7 +149,7 @@ func (p *TSocket) Write(buf []byte) (int, error) {
|
||||
return p.conn.Write(buf)
|
||||
}
|
||||
|
||||
func (p *TSocket) Flush() error {
|
||||
func (p *TSocket) Flush(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"time"
|
||||
@@ -158,7 +159,7 @@ func (p *TSSLSocket) Write(buf []byte) (int, error) {
|
||||
return p.conn.Write(buf)
|
||||
}
|
||||
|
||||
func (p *TSSLSocket) Flush() error {
|
||||
func (p *TSSLSocket) Flush(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -20,6 +20,7 @@
|
||||
package thrift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
@@ -30,6 +31,10 @@ type Flusher interface {
|
||||
Flush() (err error)
|
||||
}
|
||||
|
||||
type ContextFlusher interface {
|
||||
Flush(ctx context.Context) (err error)
|
||||
}
|
||||
|
||||
type ReadSizeProvider interface {
|
||||
RemainingBytes() (num_bytes uint64)
|
||||
}
|
||||
@@ -37,7 +42,7 @@ type ReadSizeProvider interface {
|
||||
// Encapsulates the I/O layer
|
||||
type TTransport interface {
|
||||
io.ReadWriteCloser
|
||||
Flusher
|
||||
ContextFlusher
|
||||
ReadSizeProvider
|
||||
|
||||
// Opens the transport for communication
|
||||
@@ -60,6 +65,6 @@ type TRichTransport interface {
|
||||
io.ByteReader
|
||||
io.ByteWriter
|
||||
stringWriter
|
||||
Flusher
|
||||
ContextFlusher
|
||||
ReadSizeProvider
|
||||
}
|
||||
|
||||
+3
-2
@@ -21,6 +21,7 @@ package thrift
|
||||
|
||||
import (
|
||||
"compress/zlib"
|
||||
"context"
|
||||
"io"
|
||||
"log"
|
||||
)
|
||||
@@ -91,11 +92,11 @@ func (z *TZlibTransport) Close() error {
|
||||
}
|
||||
|
||||
// Flush flushes the writer and its underlying transport.
|
||||
func (z *TZlibTransport) Flush() error {
|
||||
func (z *TZlibTransport) Flush(ctx context.Context) error {
|
||||
if err := z.writer.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
return z.transport.Flush()
|
||||
return z.transport.Flush(ctx)
|
||||
}
|
||||
|
||||
// IsOpen returns true if the transport is open
|
||||
|
||||
+50
-12
@@ -6,8 +6,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@@ -29,13 +27,43 @@ func (z zoneAddr) String() string {
|
||||
return s
|
||||
}
|
||||
|
||||
// Transport returns the protocol of the string s
|
||||
func Transport(s string) string {
|
||||
switch {
|
||||
case strings.HasPrefix(s, TransportTLS+"://"):
|
||||
return TransportTLS
|
||||
case strings.HasPrefix(s, TransportDNS+"://"):
|
||||
return TransportDNS
|
||||
case strings.HasPrefix(s, TransportGRPC+"://"):
|
||||
return TransportGRPC
|
||||
case strings.HasPrefix(s, TransportHTTPS+"://"):
|
||||
return TransportHTTPS
|
||||
}
|
||||
return TransportDNS
|
||||
}
|
||||
|
||||
// normalizeZone parses an zone string into a structured format with separate
|
||||
// host, and port portions, as well as the original input string.
|
||||
func normalizeZone(str string) (zoneAddr, error) {
|
||||
var err error
|
||||
|
||||
var trans string
|
||||
trans, str = parse.Transport(str)
|
||||
// Default to DNS if there isn't a transport protocol prefix.
|
||||
trans := TransportDNS
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(str, TransportTLS+"://"):
|
||||
trans = TransportTLS
|
||||
str = str[len(TransportTLS+"://"):]
|
||||
case strings.HasPrefix(str, TransportDNS+"://"):
|
||||
trans = TransportDNS
|
||||
str = str[len(TransportDNS+"://"):]
|
||||
case strings.HasPrefix(str, TransportGRPC+"://"):
|
||||
trans = TransportGRPC
|
||||
str = str[len(TransportGRPC+"://"):]
|
||||
case strings.HasPrefix(str, TransportHTTPS+"://"):
|
||||
trans = TransportHTTPS
|
||||
str = str[len(TransportHTTPS+"://"):]
|
||||
}
|
||||
|
||||
host, port, ipnet, err := plugin.SplitHostPort(str)
|
||||
if err != nil {
|
||||
@@ -43,15 +71,17 @@ func normalizeZone(str string) (zoneAddr, error) {
|
||||
}
|
||||
|
||||
if port == "" {
|
||||
switch trans {
|
||||
case transport.DNS:
|
||||
if trans == TransportDNS {
|
||||
port = Port
|
||||
case transport.TLS:
|
||||
port = transport.TLSPort
|
||||
case transport.GRPC:
|
||||
port = transport.GRPCPort
|
||||
case transport.HTTPS:
|
||||
port = transport.HTTPSPort
|
||||
}
|
||||
if trans == TransportTLS {
|
||||
port = TLSPort
|
||||
}
|
||||
if trans == TransportGRPC {
|
||||
port = GRPCPort
|
||||
}
|
||||
if trans == TransportHTTPS {
|
||||
port = HTTPSPort
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +103,14 @@ func SplitProtocolHostPort(address string) (protocol string, ip string, port str
|
||||
}
|
||||
}
|
||||
|
||||
// Supported transports.
|
||||
const (
|
||||
TransportDNS = "dns"
|
||||
TransportTLS = "tls"
|
||||
TransportGRPC = "grpc"
|
||||
TransportHTTPS = "https"
|
||||
)
|
||||
|
||||
type zoneOverlap struct {
|
||||
registeredAddr map[zoneAddr]zoneAddr // each zoneAddr is registered once by its key
|
||||
unboundOverlap map[zoneAddr]zoneAddr // the "no bind" equiv ZoneAdddr is registered by its original key
|
||||
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
// +build go1.11
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd
|
||||
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/log"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func reuseportControl(network, address string, c syscall.RawConn) error {
|
||||
c.Control(func(fd uintptr) {
|
||||
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
|
||||
log.Warningf("Failed to set SO_REUSEPORT on socket: %s", err)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func listen(network, addr string) (net.Listener, error) {
|
||||
lc := net.ListenConfig{Control: reuseportControl}
|
||||
return lc.Listen(context.Background(), network, addr)
|
||||
}
|
||||
|
||||
func listenPacket(network, addr string) (net.PacketConn, error) {
|
||||
lc := net.ListenConfig{Control: reuseportControl}
|
||||
return lc.ListenPacket(context.Background(), network, addr)
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
// +build !go1.11 !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
|
||||
|
||||
package dnsserver
|
||||
|
||||
import "net"
|
||||
|
||||
func listen(network, addr string) (net.Listener, error) { return net.Listen(network, addr) }
|
||||
|
||||
func listenPacket(network, addr string) (net.PacketConn, error) {
|
||||
return net.ListenPacket(network, addr)
|
||||
}
|
||||
+15
-9
@@ -9,8 +9,6 @@ import (
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyfile"
|
||||
@@ -113,29 +111,29 @@ func (h *dnsContext) MakeServers() ([]caddy.Server, error) {
|
||||
var servers []caddy.Server
|
||||
for addr, group := range groups {
|
||||
// switch on addr
|
||||
switch tr, _ := parse.Transport(addr); tr {
|
||||
case transport.DNS:
|
||||
switch Transport(addr) {
|
||||
case TransportDNS:
|
||||
s, err := NewServer(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
servers = append(servers, s)
|
||||
|
||||
case transport.TLS:
|
||||
case TransportTLS:
|
||||
s, err := NewServerTLS(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
servers = append(servers, s)
|
||||
|
||||
case transport.GRPC:
|
||||
case TransportGRPC:
|
||||
s, err := NewServergRPC(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
servers = append(servers, s)
|
||||
|
||||
case transport.HTTPS:
|
||||
case TransportHTTPS:
|
||||
s, err := NewServerHTTPS(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -236,8 +234,16 @@ func groupConfigsByListenAddr(configs []*Config) (map[string][]*Config, error) {
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
// DefaultPort is the default port.
|
||||
const DefaultPort = transport.Port
|
||||
const (
|
||||
// DefaultPort is the default port.
|
||||
DefaultPort = "53"
|
||||
// TLSPort is the default port for DNS-over-TLS.
|
||||
TLSPort = "853"
|
||||
// GRPCPort is the default port for DNS-over-gRPC.
|
||||
GRPCPort = "443"
|
||||
// HTTPSPort is the default port for DNS-over-HTTPS.
|
||||
HTTPSPort = "443"
|
||||
)
|
||||
|
||||
// These "soft defaults" are configurable by
|
||||
// command line flags, etc.
|
||||
|
||||
+2
-6
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/coredns/coredns/plugin/pkg/log"
|
||||
"github.com/coredns/coredns/plugin/pkg/rcode"
|
||||
"github.com/coredns/coredns/plugin/pkg/trace"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
@@ -135,7 +134,7 @@ func (s *Server) ServePacket(p net.PacketConn) error {
|
||||
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (s *Server) Listen() (net.Listener, error) {
|
||||
l, err := listen("tcp", s.Addr[len(transport.DNS+"://"):])
|
||||
l, err := net.Listen("tcp", s.Addr[len(TransportDNS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -144,7 +143,7 @@ func (s *Server) Listen() (net.Listener, error) {
|
||||
|
||||
// ListenPacket implements caddy.UDPServer interface.
|
||||
func (s *Server) ListenPacket() (net.PacketConn, error) {
|
||||
p, err := listenPacket("udp", s.Addr[len(transport.DNS+"://"):])
|
||||
p, err := net.ListenPacket("udp", s.Addr[len(TransportDNS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -238,9 +237,6 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
||||
|
||||
var dshandler *Config
|
||||
|
||||
// Wrap the response writer in a ScrubWriter so we automatically make the reply fit in the client's buffer.
|
||||
w = request.NewScrubWriter(r, w)
|
||||
|
||||
for {
|
||||
l := len(q[off:])
|
||||
for i := 0; i < l; i++ {
|
||||
|
||||
+2
-3
@@ -8,7 +8,6 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/coredns/coredns/pb"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
"github.com/coredns/coredns/plugin/pkg/watch"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
|
||||
@@ -74,7 +73,7 @@ func (s *ServergRPC) ServePacket(p net.PacketConn) error { return nil }
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (s *ServergRPC) Listen() (net.Listener, error) {
|
||||
|
||||
l, err := net.Listen("tcp", s.Addr[len(transport.GRPC+"://"):])
|
||||
l, err := net.Listen("tcp", s.Addr[len(TransportGRPC+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -91,7 +90,7 @@ func (s *ServergRPC) OnStartupComplete() {
|
||||
return
|
||||
}
|
||||
|
||||
out := startUpZones(transport.GRPC+"://", s.Addr, s.zones)
|
||||
out := startUpZones(TransportGRPC+"://", s.Addr, s.zones)
|
||||
if out != "" {
|
||||
fmt.Print(out)
|
||||
}
|
||||
|
||||
+2
-3
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/coredns/coredns/plugin/pkg/doh"
|
||||
"github.com/coredns/coredns/plugin/pkg/response"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
)
|
||||
|
||||
// ServerHTTPS represents an instance of a DNS-over-HTTPS server.
|
||||
@@ -61,7 +60,7 @@ func (s *ServerHTTPS) ServePacket(p net.PacketConn) error { return nil }
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (s *ServerHTTPS) Listen() (net.Listener, error) {
|
||||
|
||||
l, err := net.Listen("tcp", s.Addr[len(transport.HTTPS+"://"):])
|
||||
l, err := net.Listen("tcp", s.Addr[len(TransportHTTPS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -78,7 +77,7 @@ func (s *ServerHTTPS) OnStartupComplete() {
|
||||
return
|
||||
}
|
||||
|
||||
out := startUpZones(transport.HTTPS+"://", s.Addr, s.zones)
|
||||
out := startUpZones(TransportHTTPS+"://", s.Addr, s.zones)
|
||||
if out != "" {
|
||||
fmt.Print(out)
|
||||
}
|
||||
|
||||
+2
-4
@@ -6,8 +6,6 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -57,7 +55,7 @@ func (s *ServerTLS) ServePacket(p net.PacketConn) error { return nil }
|
||||
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (s *ServerTLS) Listen() (net.Listener, error) {
|
||||
l, err := net.Listen("tcp", s.Addr[len(transport.TLS+"://"):])
|
||||
l, err := net.Listen("tcp", s.Addr[len(TransportTLS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -74,7 +72,7 @@ func (s *ServerTLS) OnStartupComplete() {
|
||||
return
|
||||
}
|
||||
|
||||
out := startUpZones(transport.TLS+"://", s.Addr, s.zones)
|
||||
out := startUpZones(TransportTLS+"://", s.Addr, s.zones)
|
||||
if out != "" {
|
||||
fmt.Print(out)
|
||||
}
|
||||
|
||||
-1
@@ -39,7 +39,6 @@ var Directives = []string{
|
||||
"auto",
|
||||
"secondary",
|
||||
"etcd",
|
||||
"loop",
|
||||
"forward",
|
||||
"proxy",
|
||||
"erratic",
|
||||
|
||||
+2
-2
@@ -42,7 +42,7 @@ func Run() {
|
||||
caddy.TrapSignals()
|
||||
|
||||
// Reset flag.CommandLine to get rid of unwanted flags for instance from glog (used in kubernetes).
|
||||
// And read the ones we want to keep.
|
||||
// And readd the once we want to keep.
|
||||
flag.VisitAll(func(f *flag.Flag) {
|
||||
if _, ok := flagsBlacklist[f.Name]; ok {
|
||||
return
|
||||
@@ -62,7 +62,7 @@ func Run() {
|
||||
}
|
||||
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetFlags(0) // Set to 0 because we're doing our own time, with timezone
|
||||
log.SetFlags(log.LstdFlags)
|
||||
|
||||
if version {
|
||||
showVersion()
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package coremain
|
||||
|
||||
// Various CoreDNS constants.
|
||||
const (
|
||||
CoreVersion = "1.2.6"
|
||||
CoreVersion = "1.2.0"
|
||||
coreName = "CoreDNS"
|
||||
serverType = "dns"
|
||||
)
|
||||
|
||||
+22
-26
@@ -40,22 +40,24 @@ func A(b ServiceBackend, zone string, state request.Request, previousRecords []d
|
||||
if dnsutil.DuplicateCNAME(newRecord, previousRecords) {
|
||||
continue
|
||||
}
|
||||
if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) {
|
||||
state1 := state.NewWithQuestion(serv.Host, state.QType())
|
||||
state1.Zone = zone
|
||||
nextRecords, err := A(b, zone, state1, append(previousRecords, newRecord), opt)
|
||||
|
||||
if err == nil {
|
||||
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||
if len(nextRecords) > 0 {
|
||||
records = append(records, newRecord)
|
||||
records = append(records, nextRecords...)
|
||||
}
|
||||
state1 := state.NewWithQuestion(serv.Host, state.QType())
|
||||
nextRecords, err := A(b, zone, state1, append(previousRecords, newRecord), opt)
|
||||
|
||||
if err == nil {
|
||||
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||
if len(nextRecords) > 0 {
|
||||
records = append(records, newRecord)
|
||||
records = append(records, nextRecords...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// This means we can not complete the CNAME, try to look else where.
|
||||
target := newRecord.Target
|
||||
if dns.IsSubDomain(zone, target) {
|
||||
// We should already have found it
|
||||
continue
|
||||
}
|
||||
// Lookup
|
||||
m1, e1 := b.Lookup(state, target, state.QType())
|
||||
if e1 != nil {
|
||||
@@ -108,20 +110,19 @@ func AAAA(b ServiceBackend, zone string, state request.Request, previousRecords
|
||||
if dnsutil.DuplicateCNAME(newRecord, previousRecords) {
|
||||
continue
|
||||
}
|
||||
if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) {
|
||||
state1 := state.NewWithQuestion(serv.Host, state.QType())
|
||||
state1.Zone = zone
|
||||
nextRecords, err := AAAA(b, zone, state1, append(previousRecords, newRecord), opt)
|
||||
|
||||
if err == nil {
|
||||
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||
if len(nextRecords) > 0 {
|
||||
records = append(records, newRecord)
|
||||
records = append(records, nextRecords...)
|
||||
}
|
||||
state1 := state.NewWithQuestion(serv.Host, state.QType())
|
||||
nextRecords, err := AAAA(b, zone, state1, append(previousRecords, newRecord), opt)
|
||||
|
||||
if err == nil {
|
||||
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||
if len(nextRecords) > 0 {
|
||||
records = append(records, newRecord)
|
||||
records = append(records, nextRecords...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// This means we can not complete the CNAME, try to look else where.
|
||||
target := newRecord.Target
|
||||
m1, e1 := b.Lookup(state, target, state.QType())
|
||||
@@ -172,11 +173,6 @@ func SRV(b ServiceBackend, zone string, state request.Request, opt Options) (rec
|
||||
w[serv.Priority] += weight
|
||||
}
|
||||
for _, serv := range services {
|
||||
// Don't add the entry if the port is -1 (invalid). The kubernetes plugin uses port -1 when a service/endpoint
|
||||
// does not have any declared ports.
|
||||
if serv.Port == -1 {
|
||||
continue
|
||||
}
|
||||
w1 := 100.0 / float64(w[serv.Priority])
|
||||
if serv.Weight == 0 {
|
||||
w1 *= 100
|
||||
@@ -446,7 +442,7 @@ func checkForApex(b ServiceBackend, zone string, state request.Request, opt Opti
|
||||
// this is equivalent to the NS search code.
|
||||
old := state.QName()
|
||||
state.Clear()
|
||||
state.Req.Question[0].Name = dnsutil.Join("apex.dns", zone)
|
||||
state.Req.Question[0].Name = dnsutil.Join([]string{"apex.dns", zone})
|
||||
|
||||
services, err := b.Services(state, false, opt)
|
||||
if err == nil {
|
||||
|
||||
+9
-22
@@ -24,15 +24,16 @@ cache [TTL] [ZONES...]
|
||||
* **ZONES** zones it should cache for. If empty, the zones from the configuration block are used.
|
||||
|
||||
Each element in the cache is cached according to its TTL (with **TTL** as the max).
|
||||
A cache is divided into 256 shards, each holding up to 39 items by default - for a total size
|
||||
of 256 * 39 = 9984 items.
|
||||
For the negative cache, the SOA's MinTTL value is used. A TTL of zero is not allowed.
|
||||
A cache is divided into 256 shards, each holding up to 512 items by default - for a total size
|
||||
of 256 * 512 = 131,072 items.
|
||||
|
||||
If you want more control:
|
||||
|
||||
~~~ txt
|
||||
cache [TTL] [ZONES...] {
|
||||
success CAPACITY [TTL] [MINTTL]
|
||||
denial CAPACITY [TTL] [MINTTL]
|
||||
success CAPACITY [TTL]
|
||||
denial CAPACITY [TTL]
|
||||
prefetch AMOUNT [[DURATION] [PERCENTAGE%]]
|
||||
}
|
||||
~~~
|
||||
@@ -40,10 +41,8 @@ cache [TTL] [ZONES...] {
|
||||
* **TTL** and **ZONES** as above.
|
||||
* `success`, override the settings for caching successful responses. **CAPACITY** indicates the maximum
|
||||
number of packets we cache before we start evicting (*randomly*). **TTL** overrides the cache maximum TTL.
|
||||
**MINTTL** overrides the cache minimum TTL (default 5), which can be useful to limit queries to the backend.
|
||||
* `denial`, override the settings for caching denial of existence responses. **CAPACITY** indicates the maximum
|
||||
number of packets we cache before we start evicting (LRU). **TTL** overrides the cache maximum TTL.
|
||||
**MINTTL** overrides the cache minimum TTL (default 5), which can be useful to limit queries to the backend.
|
||||
There is a third category (`error`) but those responses are never cached.
|
||||
* `prefetch` will prefetch popular items when they are about to be expunged from the cache.
|
||||
Popular means **AMOUNT** queries have been seen with no gaps of **DURATION** or more between them.
|
||||
@@ -53,13 +52,11 @@ cache [TTL] [ZONES...] {
|
||||
|
||||
## Capacity and Eviction
|
||||
|
||||
If **CAPACITY** _is not_ specified, the default cache size is 9984 per cache. The minimum allowed cache size is 1024.
|
||||
If **CAPACITY** _is_ specified, the actual cache size used will be rounded down to the nearest number divisible by 256 (so all shards are equal in size).
|
||||
When specifying **CAPACITY**, the minimum cache capacity is 131,072. Specifying a lower value will be
|
||||
ignored. Specifying a **CAPACITY** of zero does not disable the cache.
|
||||
|
||||
Eviction is done per shard - i.e. when a shard reaches capacity, items are evicted from that shard. Since shards don't fill up perfectly evenly, evictions will occur before the entire cache reaches full capacity. Each shard capacity is equal to the total cache size / number of shards (256).
|
||||
|
||||
Eviction is done per shard. In effect, when a shard reaches capacity, items are evicted from that shard.
|
||||
Since shards don't fill up perfectly evenly, evictions will occur before the entire cache reaches full capacity.
|
||||
Each shard capacity is equal to the total cache size / number of shards (256). Eviction is random, not TTL based.
|
||||
Entries with 0 TTL will remain in the cache until randomly evicted when the shard reaches capacity.
|
||||
|
||||
## Metrics
|
||||
|
||||
@@ -92,13 +89,3 @@ Proxy to Google Public DNS and only cache responses for example.org (or below).
|
||||
cache example.org
|
||||
}
|
||||
~~~
|
||||
|
||||
Enable caching for all zones, keep a positive cache size of 5000 and a negative cache size of 2500:
|
||||
~~~ corefile
|
||||
. {
|
||||
cache {
|
||||
success 5000
|
||||
denial 2500
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
+42
-45
@@ -2,6 +2,7 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"hash/fnv"
|
||||
"net"
|
||||
"time"
|
||||
@@ -21,15 +22,13 @@ type Cache struct {
|
||||
Next plugin.Handler
|
||||
Zones []string
|
||||
|
||||
ncache *cache.Cache
|
||||
ncap int
|
||||
nttl time.Duration
|
||||
minnttl time.Duration
|
||||
ncache *cache.Cache
|
||||
ncap int
|
||||
nttl time.Duration
|
||||
|
||||
pcache *cache.Cache
|
||||
pcap int
|
||||
pttl time.Duration
|
||||
minpttl time.Duration
|
||||
pcache *cache.Cache
|
||||
pcap int
|
||||
pttl time.Duration
|
||||
|
||||
// Prefetch.
|
||||
prefetch int
|
||||
@@ -48,11 +47,9 @@ func New() *Cache {
|
||||
pcap: defaultCap,
|
||||
pcache: cache.New(defaultCap),
|
||||
pttl: maxTTL,
|
||||
minpttl: minTTL,
|
||||
ncap: defaultCap,
|
||||
ncache: cache.New(defaultCap),
|
||||
nttl: maxNTTL,
|
||||
minnttl: minNTTL,
|
||||
prefetch: 0,
|
||||
duration: 1 * time.Minute,
|
||||
percentage: 10,
|
||||
@@ -60,27 +57,27 @@ func New() *Cache {
|
||||
}
|
||||
}
|
||||
|
||||
// key returns key under which we store the item, -1 will be returned if we don't store the message.
|
||||
// Return key under which we store the item, -1 will be returned if we don't store the
|
||||
// message.
|
||||
// Currently we do not cache Truncated, errors zone transfers or dynamic update messages.
|
||||
// qname holds the already lowercased qname.
|
||||
func key(qname string, m *dns.Msg, t response.Type, do bool) (bool, uint64) {
|
||||
func key(m *dns.Msg, t response.Type, do bool) int {
|
||||
// We don't store truncated responses.
|
||||
if m.Truncated {
|
||||
return false, 0
|
||||
return -1
|
||||
}
|
||||
// Nor errors or Meta or Update
|
||||
if t == response.OtherError || t == response.Meta || t == response.Update {
|
||||
return false, 0
|
||||
return -1
|
||||
}
|
||||
|
||||
return true, hash(qname, m.Question[0].Qtype, do)
|
||||
return int(hash(m.Question[0].Name, m.Question[0].Qtype, do))
|
||||
}
|
||||
|
||||
var one = []byte("1")
|
||||
var zero = []byte("0")
|
||||
|
||||
func hash(qname string, qtype uint16, do bool) uint64 {
|
||||
h := fnv.New64()
|
||||
func hash(qname string, qtype uint16, do bool) uint32 {
|
||||
h := fnv.New32()
|
||||
|
||||
if do {
|
||||
h.Write(one)
|
||||
@@ -88,21 +85,19 @@ func hash(qname string, qtype uint16, do bool) uint64 {
|
||||
h.Write(zero)
|
||||
}
|
||||
|
||||
h.Write([]byte{byte(qtype >> 8)})
|
||||
h.Write([]byte{byte(qtype)})
|
||||
h.Write([]byte(qname))
|
||||
return h.Sum64()
|
||||
}
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, qtype)
|
||||
h.Write(b)
|
||||
|
||||
func computeTTL(msgTTL, minTTL, maxTTL time.Duration) time.Duration {
|
||||
ttl := msgTTL
|
||||
if ttl < minTTL {
|
||||
ttl = minTTL
|
||||
for i := range qname {
|
||||
c := qname[i]
|
||||
if c >= 'A' && c <= 'Z' {
|
||||
c += 'a' - 'A'
|
||||
}
|
||||
h.Write([]byte{c})
|
||||
}
|
||||
if ttl > maxTTL {
|
||||
ttl = maxTTL
|
||||
}
|
||||
return ttl
|
||||
|
||||
return h.Sum32()
|
||||
}
|
||||
|
||||
// ResponseWriter is a response writer that caches the reply message.
|
||||
@@ -157,17 +152,19 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
||||
}
|
||||
|
||||
// key returns empty string for anything we don't want to cache.
|
||||
hasKey, key := key(w.state.Name(), res, mt, do)
|
||||
key := key(res, mt, do)
|
||||
|
||||
msgTTL := dnsutil.MinimalTTL(res, mt)
|
||||
var duration time.Duration
|
||||
duration := w.pttl
|
||||
if mt == response.NameError || mt == response.NoData {
|
||||
duration = computeTTL(msgTTL, w.minnttl, w.nttl)
|
||||
} else {
|
||||
duration = computeTTL(msgTTL, w.minpttl, w.pttl)
|
||||
duration = w.nttl
|
||||
}
|
||||
|
||||
if hasKey && duration > 0 {
|
||||
msgTTL := dnsutil.MinimalTTL(res, mt)
|
||||
if msgTTL < duration {
|
||||
duration = msgTTL
|
||||
}
|
||||
|
||||
if key != -1 && duration > 0 {
|
||||
if w.state.Match(res) {
|
||||
w.set(res, key, mt, duration)
|
||||
cacheSize.WithLabelValues(w.server, Success).Set(float64(w.pcache.Len()))
|
||||
@@ -198,17 +195,19 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
||||
return w.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
||||
func (w *ResponseWriter) set(m *dns.Msg, key uint64, mt response.Type, duration time.Duration) {
|
||||
// duration is expected > 0
|
||||
// and key is valid
|
||||
func (w *ResponseWriter) set(m *dns.Msg, key int, mt response.Type, duration time.Duration) {
|
||||
if key == -1 || duration == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
switch mt {
|
||||
case response.NoError, response.Delegation:
|
||||
i := newItem(m, w.now(), duration)
|
||||
w.pcache.Add(key, i)
|
||||
w.pcache.Add(uint32(key), i)
|
||||
|
||||
case response.NameError, response.NoData:
|
||||
i := newItem(m, w.now(), duration)
|
||||
w.ncache.Add(key, i)
|
||||
w.ncache.Add(uint32(key), i)
|
||||
|
||||
case response.OtherError:
|
||||
// don't cache these
|
||||
@@ -229,9 +228,7 @@ func (w *ResponseWriter) Write(buf []byte) (int, error) {
|
||||
|
||||
const (
|
||||
maxTTL = dnsutil.MaximumDefaulTTL
|
||||
minTTL = dnsutil.MinimalDefaultTTL
|
||||
maxNTTL = dnsutil.MaximumDefaulTTL / 2
|
||||
minNTTL = dnsutil.MinimalDefaultTTL
|
||||
|
||||
defaultCap = 10000 // default capacity of the cache.
|
||||
|
||||
|
||||
+5
@@ -3,6 +3,7 @@ package cache
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
@@ -30,6 +31,8 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
||||
if i != nil && found {
|
||||
resp := i.toMsg(r, now)
|
||||
|
||||
state.SizeAndDo(resp)
|
||||
resp, _ = state.Scrub(resp)
|
||||
w.WriteMsg(resp)
|
||||
|
||||
if c.prefetch > 0 {
|
||||
@@ -125,3 +128,5 @@ var (
|
||||
Help: "The number responses that are not cached, because the reply is malformed.",
|
||||
}, []string{"server"})
|
||||
)
|
||||
|
||||
var once sync.Once
|
||||
|
||||
+5
-25
@@ -34,9 +34,11 @@ func setup(c *caddy.Controller) error {
|
||||
})
|
||||
|
||||
c.OnStartup(func() error {
|
||||
metrics.MustRegister(c,
|
||||
cacheSize, cacheHits, cacheMisses,
|
||||
cachePrefetches, cacheDrops)
|
||||
once.Do(func() {
|
||||
metrics.MustRegister(c,
|
||||
cacheSize, cacheHits, cacheMisses,
|
||||
cachePrefetches, cacheDrops)
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -99,17 +101,6 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
|
||||
return nil, fmt.Errorf("cache TTL can not be zero or negative: %d", pttl)
|
||||
}
|
||||
ca.pttl = time.Duration(pttl) * time.Second
|
||||
if len(args) > 2 {
|
||||
minpttl, err := strconv.Atoi(args[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Reserve < 0
|
||||
if minpttl < 0 {
|
||||
return nil, fmt.Errorf("cache min TTL can not be negative: %d", minpttl)
|
||||
}
|
||||
ca.minpttl = time.Duration(minpttl) * time.Second
|
||||
}
|
||||
}
|
||||
case Denial:
|
||||
args := c.RemainingArgs()
|
||||
@@ -131,17 +122,6 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
|
||||
return nil, fmt.Errorf("cache TTL can not be zero or negative: %d", nttl)
|
||||
}
|
||||
ca.nttl = time.Duration(nttl) * time.Second
|
||||
if len(args) > 2 {
|
||||
minnttl, err := strconv.Atoi(args[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Reserve < 0
|
||||
if minnttl < 0 {
|
||||
return nil, fmt.Errorf("cache min TTL can not be negative: %d", minnttl)
|
||||
}
|
||||
ca.minnttl = time.Duration(minnttl) * time.Second
|
||||
}
|
||||
}
|
||||
case "prefetch":
|
||||
args := c.RemainingArgs()
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ func TapperFromContext(ctx context.Context) (t Tapper) {
|
||||
}
|
||||
|
||||
// TapMessage implements Tapper.
|
||||
func (h Dnstap) TapMessage(m *tap.Message) {
|
||||
func (h *Dnstap) TapMessage(m *tap.Message) {
|
||||
t := tap.Dnstap_MESSAGE
|
||||
h.IO.Dnstap(tap.Dnstap{
|
||||
Type: &t,
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@ import (
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/dnstap/dnstapio"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyfile"
|
||||
@@ -44,7 +44,7 @@ func parseConfig(d *caddyfile.Dispenser) (c config, err error) {
|
||||
|
||||
if strings.HasPrefix(c.target, "tcp://") {
|
||||
// remote IP endpoint
|
||||
servers, err := parse.HostPortOrFile(c.target[6:])
|
||||
servers, err := dnsutil.ParseHostPortOrFile(c.target[6:])
|
||||
if err != nil {
|
||||
return c, d.ArgErr()
|
||||
}
|
||||
|
||||
+1
-33
@@ -6,36 +6,16 @@
|
||||
|
||||
## Description
|
||||
|
||||
Any errors encountered during the query processing will be printed to standard output. The errors of particular type can be consolidated and printed once per some period of time.
|
||||
Any errors encountered during the query processing will be printed to standard output.
|
||||
|
||||
This plugin can only be used once per Server Block.
|
||||
|
||||
## Syntax
|
||||
|
||||
The basic syntax is:
|
||||
|
||||
~~~
|
||||
errors
|
||||
~~~
|
||||
|
||||
Extra knobs are available with an expanded syntax:
|
||||
|
||||
~~~
|
||||
errors {
|
||||
consolidate DURATION REGEXP
|
||||
}
|
||||
~~~
|
||||
|
||||
Option `consolidate` allows collecting several error messages matching the regular expression **REGEXP** during **DURATION**. After the **DURATION** since receiving the first such message, the consolidated message will be printed to standard output, e.g.
|
||||
|
||||
~~~
|
||||
2 errors like '^read udp .* i/o timeout$' occurred in last 30s
|
||||
~~~
|
||||
|
||||
Multiple `consolidate` options with different **DURATION** and **REGEXP** are allowed. In case if some error message corresponds to several defined regular expressions the message will be associated with the first appropriate **REGEXP**.
|
||||
|
||||
For better performance, it's recomended to use the `^` or `$` metacharacters in regular expression when filtering error messages by prefix or suffix, e.g. `^failed to .*`, or `.* timeout$`.
|
||||
|
||||
## Examples
|
||||
|
||||
Use the *whoami* to respond to queries and Log errors to standard output.
|
||||
@@ -46,15 +26,3 @@ Use the *whoami* to respond to queries and Log errors to standard output.
|
||||
errors
|
||||
}
|
||||
~~~
|
||||
|
||||
Use the *forward* to resolve queries via 8.8.8.8 and print consolidated error messages for errors with suffix " i/o timeout" or with prefix "Failed to ".
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
forward . 8.8.8.8
|
||||
errors {
|
||||
consolidate 5m ".* i/o timeout$"
|
||||
consolidate 30s "^Failed to .+"
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
+5
-88
@@ -1,12 +1,8 @@
|
||||
// Package errors implements an error handling plugin.
|
||||
// Package errors implements an HTTP error handling plugin.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||
@@ -15,98 +11,19 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
var log = clog.NewWithPlugin("errors")
|
||||
|
||||
type pattern struct {
|
||||
ptimer unsafe.Pointer
|
||||
count uint32
|
||||
period time.Duration
|
||||
pattern *regexp.Regexp
|
||||
}
|
||||
|
||||
func (p *pattern) timer() *time.Timer {
|
||||
return (*time.Timer)(atomic.LoadPointer(&p.ptimer))
|
||||
}
|
||||
|
||||
func (p *pattern) setTimer(t *time.Timer) {
|
||||
atomic.StorePointer(&p.ptimer, unsafe.Pointer(t))
|
||||
}
|
||||
|
||||
// errorHandler handles DNS errors (and errors from other plugin).
|
||||
type errorHandler struct {
|
||||
patterns []*pattern
|
||||
eLogger func(int, string, string, string)
|
||||
cLogger func(uint32, string, time.Duration)
|
||||
stopFlag uint32
|
||||
Next plugin.Handler
|
||||
}
|
||||
|
||||
func newErrorHandler() *errorHandler {
|
||||
return &errorHandler{eLogger: errorLogger, cLogger: consLogger}
|
||||
}
|
||||
|
||||
func errorLogger(code int, qName, qType, err string) {
|
||||
log.Errorf("%d %s %s: %s", code, qName, qType, err)
|
||||
}
|
||||
|
||||
func consLogger(cnt uint32, pattern string, p time.Duration) {
|
||||
log.Errorf("%d errors like '%s' occured in last %s", cnt, pattern, p)
|
||||
}
|
||||
|
||||
func (h *errorHandler) logPattern(i int) {
|
||||
cnt := atomic.SwapUint32(&h.patterns[i].count, 0)
|
||||
if cnt > 0 {
|
||||
h.cLogger(cnt, h.patterns[i].pattern.String(), h.patterns[i].period)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *errorHandler) inc(i int) bool {
|
||||
if atomic.LoadUint32(&h.stopFlag) > 0 {
|
||||
return false
|
||||
}
|
||||
if atomic.AddUint32(&h.patterns[i].count, 1) == 1 {
|
||||
ind := i
|
||||
t := time.AfterFunc(h.patterns[ind].period, func() {
|
||||
h.logPattern(ind)
|
||||
})
|
||||
h.patterns[ind].setTimer(t)
|
||||
if atomic.LoadUint32(&h.stopFlag) > 0 && t.Stop() {
|
||||
h.logPattern(ind)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *errorHandler) stop() {
|
||||
atomic.StoreUint32(&h.stopFlag, 1)
|
||||
for i := range h.patterns {
|
||||
t := h.patterns[i].timer()
|
||||
if t != nil && t.Stop() {
|
||||
h.logPattern(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
type errorHandler struct{ Next plugin.Handler }
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (h *errorHandler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
func (h errorHandler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
rcode, err := plugin.NextOrFailure(h.Name(), h.Next, ctx, w, r)
|
||||
|
||||
if err != nil {
|
||||
strErr := err.Error()
|
||||
for i := range h.patterns {
|
||||
if h.patterns[i].pattern.MatchString(strErr) {
|
||||
if h.inc(i) {
|
||||
return rcode, err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
state := request.Request{W: w, Req: r}
|
||||
h.eLogger(rcode, state.Name(), state.Type(), strErr)
|
||||
clog.Errorf("%d %s %s: %v", rcode, state.Name(), state.Type(), err)
|
||||
}
|
||||
|
||||
return rcode, err
|
||||
}
|
||||
|
||||
// Name implements the plugin.Handler interface.
|
||||
func (h *errorHandler) Name() string { return "errors" }
|
||||
func (h errorHandler) Name() string { return "errors" }
|
||||
|
||||
+6
-40
@@ -1,8 +1,7 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"time"
|
||||
"fmt"
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
@@ -23,11 +22,6 @@ func setup(c *caddy.Controller) error {
|
||||
return plugin.Error("errors", err)
|
||||
}
|
||||
|
||||
c.OnShutdown(func() error {
|
||||
handler.stop()
|
||||
return nil
|
||||
})
|
||||
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
handler.Next = next
|
||||
return handler
|
||||
@@ -36,13 +30,13 @@ func setup(c *caddy.Controller) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func errorsParse(c *caddy.Controller) (*errorHandler, error) {
|
||||
handler := newErrorHandler()
|
||||
func errorsParse(c *caddy.Controller) (errorHandler, error) {
|
||||
handler := errorHandler{}
|
||||
|
||||
i := 0
|
||||
for c.Next() {
|
||||
if i > 0 {
|
||||
return nil, plugin.ErrOnce
|
||||
return handler, plugin.ErrOnce
|
||||
}
|
||||
i++
|
||||
|
||||
@@ -51,39 +45,11 @@ func errorsParse(c *caddy.Controller) (*errorHandler, error) {
|
||||
case 0:
|
||||
case 1:
|
||||
if args[0] != "stdout" {
|
||||
return nil, c.Errf("invalid log file: %s", args[0])
|
||||
return handler, fmt.Errorf("invalid log file: %s", args[0])
|
||||
}
|
||||
default:
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
|
||||
for c.NextBlock() {
|
||||
if err := parseBlock(c, handler); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler, c.ArgErr()
|
||||
}
|
||||
}
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
func parseBlock(c *caddy.Controller, h *errorHandler) error {
|
||||
if c.Val() != "consolidate" {
|
||||
return c.SyntaxErr("consolidate")
|
||||
}
|
||||
|
||||
args := c.RemainingArgs()
|
||||
if len(args) != 2 {
|
||||
return c.ArgErr()
|
||||
}
|
||||
p, err := time.ParseDuration(args[0])
|
||||
if err != nil {
|
||||
return c.Err(err.Error())
|
||||
}
|
||||
re, err := regexp.Compile(args[1])
|
||||
if err != nil {
|
||||
return c.Err(err.Error())
|
||||
}
|
||||
h.patterns = append(h.patterns, &pattern{period: p, pattern: re})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ func Domain(s string) string {
|
||||
for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
return dnsutil.Join(l[1 : len(l)-1]...)
|
||||
return dnsutil.Join(l[1 : len(l)-1])
|
||||
}
|
||||
|
||||
// PathWithWildcard ascts as Path, but if a name contains wildcards (* or any), the name will be
|
||||
|
||||
+1
-1
@@ -164,7 +164,7 @@ func targetStrip(name string, targetStrip int) string {
|
||||
offset, end = dns.NextLabel(name, offset)
|
||||
}
|
||||
if end {
|
||||
// We overshot the name, use the original one.
|
||||
// We overshot the name, use the orignal one.
|
||||
offset = 0
|
||||
}
|
||||
name = name[offset:]
|
||||
|
||||
+2
-5
@@ -27,7 +27,6 @@ If you want to round robin A and AAAA responses look at the *loadbalance* plugin
|
||||
~~~
|
||||
file DBFILE [ZONES... ] {
|
||||
transfer to ADDRESS...
|
||||
reload DURATION
|
||||
no_reload
|
||||
upstream [ADDRESS...]
|
||||
}
|
||||
@@ -37,10 +36,8 @@ file DBFILE [ZONES... ] {
|
||||
the direction. **ADDRESS** must be denoted in CIDR notation (127.0.0.1/32 etc.) or just as plain
|
||||
addresses. The special wildcard `*` means: the entire internet (only valid for 'transfer to').
|
||||
When an address is specified a notify message will be send whenever the zone is reloaded.
|
||||
* `reload` interval to perform reload of zone if SOA version changes. Default is one minute.
|
||||
Value of `0` means to not scan for changes and reload. eg. `30s` checks zonefile every 30 seconds
|
||||
and reloads zone when serial changes.
|
||||
* `no_reload` deprecated. Sets reload to 0.
|
||||
* `no_reload` by default CoreDNS will try to reload a zone every minute and reloads if the
|
||||
SOA's serial has changed. This option disables that behavior.
|
||||
* `upstream` defines upstream resolvers to be used resolve external names found (think CNAMEs)
|
||||
pointing to external names. This is only really useful when CoreDNS is configured as a proxy, for
|
||||
normal authoritative serving you don't need *or* want to use this. **ADDRESS** can be an IP
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ func substituteDNAME(qname, owner, target string) string {
|
||||
labels := dns.SplitDomainName(qname)
|
||||
labels = append(labels[0:len(labels)-dns.CountLabel(owner)], dns.SplitDomainName(target)...)
|
||||
|
||||
return dnsutil.Join(labels...)
|
||||
return dnsutil.Join(labels)
|
||||
}
|
||||
|
||||
return ""
|
||||
|
||||
+8
-8
@@ -98,6 +98,8 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
||||
return dns.RcodeServerFailure, nil
|
||||
}
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
@@ -120,18 +122,16 @@ func (s *serialErr) Error() string {
|
||||
// If serial >= 0 it will reload the zone, if the SOA hasn't changed
|
||||
// it returns an error indicating nothing was read.
|
||||
func Parse(f io.Reader, origin, fileName string, serial int64) (*Zone, error) {
|
||||
|
||||
zp := dns.NewZoneParser(f, dns.Fqdn(origin), fileName)
|
||||
zp.SetIncludeAllowed(true)
|
||||
tokens := dns.ParseZone(f, dns.Fqdn(origin), fileName)
|
||||
z := NewZone(origin, fileName)
|
||||
seenSOA := false
|
||||
for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
|
||||
if err := zp.Err(); err != nil {
|
||||
return nil, err
|
||||
for x := range tokens {
|
||||
if x.Error != nil {
|
||||
return nil, x.Error
|
||||
}
|
||||
|
||||
if !seenSOA && serial >= 0 {
|
||||
if s, ok := rr.(*dns.SOA); ok {
|
||||
if s, ok := x.RR.(*dns.SOA); ok {
|
||||
if s.Serial == uint32(serial) { // same serial
|
||||
return nil, &serialErr{err: "no change in SOA serial", origin: origin, zone: fileName, serial: serial}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func Parse(f io.Reader, origin, fileName string, serial int64) (*Zone, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := z.Insert(rr); err != nil {
|
||||
if err := z.Insert(x.RR); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,11 +30,11 @@ func (z *Zone) Lookup(state request.Request, qname string) ([]dns.RR, []dns.RR,
|
||||
qtype := state.QType()
|
||||
do := state.Do()
|
||||
|
||||
if 0 < z.ReloadInterval {
|
||||
if !z.NoReload {
|
||||
z.reloadMu.RLock()
|
||||
}
|
||||
defer func() {
|
||||
if 0 < z.ReloadInterval {
|
||||
if !z.NoReload {
|
||||
z.reloadMu.RUnlock()
|
||||
}
|
||||
}()
|
||||
|
||||
+4
-10
@@ -5,14 +5,15 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// TickTime is clock resolution. By default ticks every second. Handler checks if reloadInterval has been reached on every tick.
|
||||
var TickTime = 1 * time.Second
|
||||
// TickTime is the default time we use to reload zone. Exported to be tweaked in tests.
|
||||
var TickTime = 1 * time.Minute
|
||||
|
||||
// Reload reloads a zone when it is changed on disk. If z.NoRoload is true, no reloading will be done.
|
||||
func (z *Zone) Reload() error {
|
||||
if z.ReloadInterval == 0 {
|
||||
if z.NoReload {
|
||||
return nil
|
||||
}
|
||||
|
||||
tick := time.NewTicker(TickTime)
|
||||
|
||||
go func() {
|
||||
@@ -21,13 +22,6 @@ func (z *Zone) Reload() error {
|
||||
select {
|
||||
|
||||
case <-tick.C:
|
||||
if z.LastReloaded.Add(z.ReloadInterval).After(time.Now()) {
|
||||
//reload interval not reached yet
|
||||
continue
|
||||
}
|
||||
//saving timestamp of last attempted reload
|
||||
z.LastReloaded = time.Now()
|
||||
|
||||
zFile := z.File()
|
||||
reader, err := os.Open(zFile)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ func less(a, b uint32) bool {
|
||||
|
||||
// Update updates the secondary zone according to its SOA. It will run for the life time of the server
|
||||
// and uses the SOA parameters. Every refresh it will check for a new SOA number. If that fails (for all
|
||||
// server) it will retry every retry interval. If the zone failed to transfer before the expire, the zone
|
||||
// server) it wil retry every retry interval. If the zone failed to transfer before the expire, the zone
|
||||
// will be marked expired.
|
||||
func (z *Zone) Update() error {
|
||||
// If we don't have a SOA, we don't have a zone, wait for it to appear.
|
||||
|
||||
+8
-15
@@ -2,8 +2,7 @@ package file
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
"path"
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
@@ -54,6 +53,7 @@ func setup(c *caddy.Controller) error {
|
||||
func fileParse(c *caddy.Controller) (Zones, error) {
|
||||
z := make(map[string]*Zone)
|
||||
names := []string{}
|
||||
origins := []string{}
|
||||
|
||||
config := dnsserver.GetConfig(c)
|
||||
|
||||
@@ -64,15 +64,15 @@ func fileParse(c *caddy.Controller) (Zones, error) {
|
||||
}
|
||||
fileName := c.Val()
|
||||
|
||||
origins := make([]string, len(c.ServerBlockKeys))
|
||||
origins = make([]string, len(c.ServerBlockKeys))
|
||||
copy(origins, c.ServerBlockKeys)
|
||||
args := c.RemainingArgs()
|
||||
if len(args) > 0 {
|
||||
origins = args
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(fileName) && config.Root != "" {
|
||||
fileName = filepath.Join(config.Root, fileName)
|
||||
if !path.IsAbs(fileName) && config.Root != "" {
|
||||
fileName = path.Join(config.Root, fileName)
|
||||
}
|
||||
|
||||
reader, err := os.Open(fileName)
|
||||
@@ -92,7 +92,7 @@ func fileParse(c *caddy.Controller) (Zones, error) {
|
||||
names = append(names, origins[i])
|
||||
}
|
||||
|
||||
reload := 1 * time.Minute
|
||||
noReload := false
|
||||
upstr := upstream.Upstream{}
|
||||
t := []string{}
|
||||
var e error
|
||||
@@ -105,15 +105,8 @@ func fileParse(c *caddy.Controller) (Zones, error) {
|
||||
return Zones{}, e
|
||||
}
|
||||
|
||||
case "reload":
|
||||
d, err := time.ParseDuration(c.RemainingArgs()[0])
|
||||
if err != nil {
|
||||
return Zones{}, plugin.Error("file", err)
|
||||
}
|
||||
reload = d
|
||||
|
||||
case "no_reload":
|
||||
reload = 0
|
||||
noReload = true
|
||||
|
||||
case "upstream":
|
||||
args := c.RemainingArgs()
|
||||
@@ -130,7 +123,7 @@ func fileParse(c *caddy.Controller) (Zones, error) {
|
||||
if t != nil {
|
||||
z[origin].TransferTo = append(z[origin].TransferTo, t...)
|
||||
}
|
||||
z[origin].ReloadInterval = reload
|
||||
z[origin].NoReload = noReload
|
||||
z[origin].Upstream = upstr
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package file
|
||||
|
||||
// OnShutdown shuts down any running go-routines for this zone.
|
||||
func (z *Zone) OnShutdown() error {
|
||||
if 0 < z.ReloadInterval {
|
||||
if !z.NoReload {
|
||||
z.reloadShutdown <- true
|
||||
}
|
||||
return nil
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ func (x Xfr) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (in
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
||||
// Name implements the plugin.Handler interface.
|
||||
// Name implements the plugin.Hander interface.
|
||||
func (x Xfr) Name() string { return "xfr" }
|
||||
|
||||
const transferLength = 1000 // Start a new envelop after message reaches this size in bytes. Intentionally small to test multi envelope parsing.
|
||||
|
||||
+5
-8
@@ -3,10 +3,9 @@ package file
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin/file/tree"
|
||||
"github.com/coredns/coredns/plugin/pkg/upstream"
|
||||
@@ -28,8 +27,7 @@ type Zone struct {
|
||||
TransferFrom []string
|
||||
Expired *bool
|
||||
|
||||
ReloadInterval time.Duration
|
||||
LastReloaded time.Time
|
||||
NoReload bool
|
||||
reloadMu sync.RWMutex
|
||||
reloadShutdown chan bool
|
||||
Upstream upstream.Upstream // Upstream for looking up names during the resolution process
|
||||
@@ -48,11 +46,10 @@ func NewZone(name, file string) *Zone {
|
||||
z := &Zone{
|
||||
origin: dns.Fqdn(name),
|
||||
origLen: dns.CountLabel(dns.Fqdn(name)),
|
||||
file: filepath.Clean(file),
|
||||
file: path.Clean(file),
|
||||
Tree: &tree.Tree{},
|
||||
Expired: new(bool),
|
||||
reloadShutdown: make(chan bool),
|
||||
LastReloaded: time.Now(),
|
||||
}
|
||||
*z.Expired = false
|
||||
|
||||
@@ -164,7 +161,7 @@ func (z *Zone) TransferAllowed(state request.Request) bool {
|
||||
// All returns all records from the zone, the first record will be the SOA record,
|
||||
// otionally followed by all RRSIG(SOA)s.
|
||||
func (z *Zone) All() []dns.RR {
|
||||
if z.ReloadInterval > 0 {
|
||||
if !z.NoReload {
|
||||
z.reloadMu.RLock()
|
||||
defer z.reloadMu.RUnlock()
|
||||
}
|
||||
@@ -206,7 +203,7 @@ func (z *Zone) nameFromRight(qname string, i int) (string, bool) {
|
||||
}
|
||||
|
||||
k := 0
|
||||
var shot bool
|
||||
shot := false
|
||||
for j := 1; j <= i; j++ {
|
||||
k, shot = dns.PrevLabel(qname, j+z.origLen)
|
||||
if shot {
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
// Package forward implements a forwarding proxy. It caches an upstream net.Conn for some time, so if the same
|
||||
// client returns the upstream's Conn will be precached. Depending on how you benchmark this looks to be
|
||||
// 50% faster than just opening a new connection for every client. It works with UDP and TCP and uses
|
||||
// 50% faster than just openening a new connection for every client. It works with UDP and TCP and uses
|
||||
// inband healthchecking.
|
||||
package forward
|
||||
|
||||
@@ -35,16 +35,16 @@ func averageTimeout(currentAvg *int64, observedDuration time.Duration, weight in
|
||||
atomic.AddInt64(currentAvg, int64(observedDuration-dt)/weight)
|
||||
}
|
||||
|
||||
func (t *Transport) dialTimeout() time.Duration {
|
||||
func (t *transport) dialTimeout() time.Duration {
|
||||
return limitTimeout(&t.avgDialTime, minDialTimeout, maxDialTimeout)
|
||||
}
|
||||
|
||||
func (t *Transport) updateDialTimeout(newDialTime time.Duration) {
|
||||
func (t *transport) updateDialTimeout(newDialTime time.Duration) {
|
||||
averageTimeout(&t.avgDialTime, newDialTime, cumulativeAvgWeight)
|
||||
}
|
||||
|
||||
// Dial dials the address configured in transport, potentially reusing a connection or creating a new one.
|
||||
func (t *Transport) Dial(proto string) (*dns.Conn, bool, error) {
|
||||
func (t *transport) Dial(proto string) (*dns.Conn, bool, error) {
|
||||
// If tls has been configured; use it.
|
||||
if t.tlsConfig != nil {
|
||||
proto = "tcp-tls"
|
||||
|
||||
+7
-4
@@ -1,6 +1,6 @@
|
||||
// Package forward implements a forwarding proxy. It caches an upstream net.Conn for some time, so if the same
|
||||
// client returns the upstream's Conn will be precached. Depending on how you benchmark this looks to be
|
||||
// 50% faster than just opening a new connection for every client. It works with UDP and TCP and uses
|
||||
// 50% faster than just openening a new connection for every client. It works with UDP and TCP and uses
|
||||
// inband healthchecking.
|
||||
package forward
|
||||
|
||||
@@ -12,15 +12,12 @@ import (
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/debug"
|
||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
ot "github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
var log = clog.NewWithPlugin("forward")
|
||||
|
||||
// Forward represents a plugin instance that can proxy requests to another (DNS) server. It has a list
|
||||
// of proxies each representing one upstream proxy.
|
||||
type Forward struct {
|
||||
@@ -151,7 +148,13 @@ func (f *Forward) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// When using force_tcp the upstream can send a message that is too big for
|
||||
// the udp buffer, hence we need to truncate the message to at least make it
|
||||
// fit the udp buffer.
|
||||
ret, _ = state.Scrub(ret)
|
||||
|
||||
w.WriteMsg(ret)
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
|
||||
+4
-7
@@ -5,8 +5,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -19,10 +17,10 @@ type HealthChecker interface {
|
||||
// dnsHc is a health checker for a DNS endpoint (DNS, and DoT).
|
||||
type dnsHc struct{ c *dns.Client }
|
||||
|
||||
// NewHealthChecker returns a new HealthChecker based on transport.
|
||||
func NewHealthChecker(trans string) HealthChecker {
|
||||
switch trans {
|
||||
case transport.DNS, transport.TLS:
|
||||
// NewHealthChecker returns a new HealthChecker based on protocol.
|
||||
func NewHealthChecker(protocol int) HealthChecker {
|
||||
switch protocol {
|
||||
case DNS, TLS:
|
||||
c := new(dns.Client)
|
||||
c.Net = "udp"
|
||||
c.ReadTimeout = 1 * time.Second
|
||||
@@ -31,7 +29,6 @@ func NewHealthChecker(trans string) HealthChecker {
|
||||
return &dnsHc{c: c}
|
||||
}
|
||||
|
||||
log.Warningf("No healthchecker for transport %q", trans)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -1,13 +1,12 @@
|
||||
// Package forward implements a forwarding proxy. It caches an upstream net.Conn for some time, so if the same
|
||||
// client returns the upstream's Conn will be precached. Depending on how you benchmark this looks to be
|
||||
// 50% faster than just opening a new connection for every client. It works with UDP and TCP and uses
|
||||
// 50% faster than just openening a new connection for every client. It works with UDP and TCP and uses
|
||||
// inband healthchecking.
|
||||
package forward
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
@@ -82,7 +81,7 @@ func (f *Forward) Lookup(state request.Request, name string, typ uint16) (*dns.M
|
||||
func NewLookup(addr []string) *Forward {
|
||||
f := New()
|
||||
for i := range addr {
|
||||
p := NewProxy(addr[i], transport.DNS)
|
||||
p := NewProxy(addr[i], DNS)
|
||||
f.SetProxy(p)
|
||||
}
|
||||
return f
|
||||
|
||||
+4
@@ -1,6 +1,8 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
@@ -46,3 +48,5 @@ var (
|
||||
Help: "Gauge of open sockets per upstream.",
|
||||
}, []string{"to"})
|
||||
)
|
||||
|
||||
var once sync.Once
|
||||
|
||||
+13
-13
@@ -15,10 +15,10 @@ type persistConn struct {
|
||||
used time.Time
|
||||
}
|
||||
|
||||
// Transport hold the persistent cache.
|
||||
type Transport struct {
|
||||
// transport hold the persistent cache.
|
||||
type transport struct {
|
||||
avgDialTime int64 // kind of average time of dial time
|
||||
conns map[string][]*persistConn // Buckets for udp, tcp and tcp-tls.
|
||||
conns map[string][]*persistConn // Buckets for udp, tcp and tcp-tls.
|
||||
expire time.Duration // After this duration a connection is expired.
|
||||
addr string
|
||||
tlsConfig *tls.Config
|
||||
@@ -29,8 +29,8 @@ type Transport struct {
|
||||
stop chan bool
|
||||
}
|
||||
|
||||
func newTransport(addr string) *Transport {
|
||||
t := &Transport{
|
||||
func newTransport(addr string) *transport {
|
||||
t := &transport{
|
||||
avgDialTime: int64(defaultDialTimeout / 2),
|
||||
conns: make(map[string][]*persistConn),
|
||||
expire: defaultExpire,
|
||||
@@ -45,7 +45,7 @@ func newTransport(addr string) *Transport {
|
||||
|
||||
// len returns the number of connection, used for metrics. Can only be safely
|
||||
// used inside connManager() because of data races.
|
||||
func (t *Transport) len() int {
|
||||
func (t *transport) len() int {
|
||||
l := 0
|
||||
for _, conns := range t.conns {
|
||||
l += len(conns)
|
||||
@@ -54,7 +54,7 @@ func (t *Transport) len() int {
|
||||
}
|
||||
|
||||
// connManagers manages the persistent connection cache for UDP and TCP.
|
||||
func (t *Transport) connManager() {
|
||||
func (t *transport) connManager() {
|
||||
ticker := time.NewTicker(t.expire)
|
||||
Wait:
|
||||
for {
|
||||
@@ -115,7 +115,7 @@ func closeConns(conns []*persistConn) {
|
||||
}
|
||||
|
||||
// cleanup removes connections from cache.
|
||||
func (t *Transport) cleanup(all bool) {
|
||||
func (t *transport) cleanup(all bool) {
|
||||
staleTime := time.Now().Add(-t.expire)
|
||||
for proto, stack := range t.conns {
|
||||
if len(stack) == 0 {
|
||||
@@ -144,19 +144,19 @@ func (t *Transport) cleanup(all bool) {
|
||||
}
|
||||
|
||||
// Yield return the connection to transport for reuse.
|
||||
func (t *Transport) Yield(c *dns.Conn) { t.yield <- c }
|
||||
func (t *transport) Yield(c *dns.Conn) { t.yield <- c }
|
||||
|
||||
// Start starts the transport's connection manager.
|
||||
func (t *Transport) Start() { go t.connManager() }
|
||||
func (t *transport) Start() { go t.connManager() }
|
||||
|
||||
// Stop stops the transport's connection manager.
|
||||
func (t *Transport) Stop() { close(t.stop) }
|
||||
func (t *transport) Stop() { close(t.stop) }
|
||||
|
||||
// SetExpire sets the connection expire time in transport.
|
||||
func (t *Transport) SetExpire(expire time.Duration) { t.expire = expire }
|
||||
func (t *transport) SetExpire(expire time.Duration) { t.expire = expire }
|
||||
|
||||
// SetTLSConfig sets the TLS config in transport.
|
||||
func (t *Transport) SetTLSConfig(cfg *tls.Config) { t.tlsConfig = cfg }
|
||||
func (t *transport) SetTLSConfig(cfg *tls.Config) { t.tlsConfig = cfg }
|
||||
|
||||
const (
|
||||
defaultExpire = 10 * time.Second
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package forward
|
||||
|
||||
// Copied from coredns/core/dnsserver/address.go
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// protocol returns the protocol of the string s. The second string returns s
|
||||
// with the prefix chopped off.
|
||||
func protocol(s string) (int, string) {
|
||||
switch {
|
||||
case strings.HasPrefix(s, _tls+"://"):
|
||||
return TLS, s[len(_tls)+3:]
|
||||
case strings.HasPrefix(s, _dns+"://"):
|
||||
return DNS, s[len(_dns)+3:]
|
||||
}
|
||||
return DNS, s
|
||||
}
|
||||
|
||||
// Supported protocols.
|
||||
const (
|
||||
DNS = iota + 1
|
||||
TLS
|
||||
)
|
||||
|
||||
const (
|
||||
_dns = "dns"
|
||||
_tls = "tls"
|
||||
)
|
||||
+3
-8
@@ -18,7 +18,7 @@ type Proxy struct {
|
||||
|
||||
// Connection caching
|
||||
expire time.Duration
|
||||
transport *Transport
|
||||
transport *transport
|
||||
|
||||
// health checking
|
||||
probe *up.Probe
|
||||
@@ -26,7 +26,7 @@ type Proxy struct {
|
||||
}
|
||||
|
||||
// NewProxy returns a new proxy.
|
||||
func NewProxy(addr, trans string) *Proxy {
|
||||
func NewProxy(addr string, protocol int) *Proxy {
|
||||
p := &Proxy{
|
||||
addr: addr,
|
||||
fails: 0,
|
||||
@@ -34,7 +34,7 @@ func NewProxy(addr, trans string) *Proxy {
|
||||
transport: newTransport(addr),
|
||||
avgRtt: int64(maxTimeout / 2),
|
||||
}
|
||||
p.health = NewHealthChecker(trans)
|
||||
p.health = NewHealthChecker(protocol)
|
||||
runtime.SetFinalizer(p, (*Proxy).finalizer)
|
||||
return p
|
||||
}
|
||||
@@ -50,11 +50,6 @@ func (p *Proxy) SetExpire(expire time.Duration) { p.transport.SetExpire(expire)
|
||||
|
||||
// Healthcheck kicks of a round of health checks for this proxy.
|
||||
func (p *Proxy) Healthcheck() {
|
||||
if p.health == nil {
|
||||
log.Warning("No healthchecker")
|
||||
return
|
||||
}
|
||||
|
||||
p.probe.Do(func() error {
|
||||
return p.health.Check(p)
|
||||
})
|
||||
|
||||
+59
-44
@@ -2,18 +2,17 @@ package forward
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/metrics"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
pkgtls "github.com/coredns/coredns/plugin/pkg/tls"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyfile"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -38,7 +37,9 @@ func setup(c *caddy.Controller) error {
|
||||
})
|
||||
|
||||
c.OnStartup(func() error {
|
||||
metrics.MustRegister(c, RequestCount, RcodeCount, RequestDuration, HealthcheckFailureCount, SocketGauge)
|
||||
once.Do(func() {
|
||||
metrics.MustRegister(c, RequestCount, RcodeCount, RequestDuration, HealthcheckFailureCount, SocketGauge)
|
||||
})
|
||||
return f.OnStartup()
|
||||
})
|
||||
|
||||
@@ -69,55 +70,69 @@ func (f *Forward) OnShutdown() error {
|
||||
func (f *Forward) Close() { f.OnShutdown() }
|
||||
|
||||
func parseForward(c *caddy.Controller) (*Forward, error) {
|
||||
var (
|
||||
f *Forward
|
||||
err error
|
||||
i int
|
||||
)
|
||||
f := New()
|
||||
|
||||
protocols := map[int]int{}
|
||||
|
||||
i := 0
|
||||
for c.Next() {
|
||||
if i > 0 {
|
||||
return nil, plugin.ErrOnce
|
||||
}
|
||||
i++
|
||||
f, err = ParseForwardStanza(&c.Dispenser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
if !c.Args(&f.from) {
|
||||
return f, c.ArgErr()
|
||||
}
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
f.from = plugin.Host(f.from).Normalize()
|
||||
|
||||
// ParseForwardStanza parses one forward stanza
|
||||
func ParseForwardStanza(c *caddyfile.Dispenser) (*Forward, error) {
|
||||
f := New()
|
||||
to := c.RemainingArgs()
|
||||
if len(to) == 0 {
|
||||
return f, c.ArgErr()
|
||||
}
|
||||
|
||||
if !c.Args(&f.from) {
|
||||
return f, c.ArgErr()
|
||||
}
|
||||
f.from = plugin.Host(f.from).Normalize()
|
||||
// A bit fiddly, but first check if we've got protocols and if so add them back in when we create the proxies.
|
||||
protocols = make(map[int]int)
|
||||
for i := range to {
|
||||
protocols[i], to[i] = protocol(to[i])
|
||||
}
|
||||
|
||||
to := c.RemainingArgs()
|
||||
if len(to) == 0 {
|
||||
return f, c.ArgErr()
|
||||
}
|
||||
|
||||
toHosts, err := parse.HostPortOrFile(to...)
|
||||
if err != nil {
|
||||
return f, err
|
||||
}
|
||||
|
||||
transports := make([]string, len(toHosts))
|
||||
for i, host := range toHosts {
|
||||
trans, h := parse.Transport(host)
|
||||
p := NewProxy(h, trans)
|
||||
f.proxies = append(f.proxies, p)
|
||||
transports[i] = trans
|
||||
}
|
||||
|
||||
for c.NextBlock() {
|
||||
if err := parseBlock(c, f); err != nil {
|
||||
// If parseHostPortOrFile expands a file with a lot of nameserver our accounting in protocols doesn't make
|
||||
// any sense anymore... For now: lets don't care.
|
||||
toHosts, err := dnsutil.ParseHostPortOrFile(to...)
|
||||
if err != nil {
|
||||
return f, err
|
||||
}
|
||||
|
||||
for i, h := range toHosts {
|
||||
// Double check the port, if e.g. is 53 and the transport is TLS make it 853.
|
||||
// This can be somewhat annoying because you *can't* have TLS on port 53 then.
|
||||
switch protocols[i] {
|
||||
case TLS:
|
||||
h1, p, err := net.SplitHostPort(h)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// This is more of a bug in dnsutil.ParseHostPortOrFile that defaults to
|
||||
// 53 because it doesn't know about the tls:// // and friends (that should be fixed). Hence
|
||||
// Fix the port number here, back to what the user intended.
|
||||
if p == "53" {
|
||||
h = net.JoinHostPort(h1, "853")
|
||||
}
|
||||
}
|
||||
|
||||
// We can't set tlsConfig here, because we haven't parsed it yet.
|
||||
// We set it below at the end of parseBlock, use nil now.
|
||||
p := NewProxy(h, protocols[i])
|
||||
f.proxies = append(f.proxies, p)
|
||||
}
|
||||
|
||||
for c.NextBlock() {
|
||||
if err := parseBlock(c, f); err != nil {
|
||||
return f, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f.tlsServerName != "" {
|
||||
@@ -125,7 +140,7 @@ func ParseForwardStanza(c *caddyfile.Dispenser) (*Forward, error) {
|
||||
}
|
||||
for i := range f.proxies {
|
||||
// Only set this for proxies that need it.
|
||||
if transports[i] == transport.TLS {
|
||||
if protocols[i] == TLS {
|
||||
f.proxies[i].SetTLSConfig(f.tlsConfig)
|
||||
}
|
||||
f.proxies[i].SetExpire(f.expire)
|
||||
@@ -133,7 +148,7 @@ func ParseForwardStanza(c *caddyfile.Dispenser) (*Forward, error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func parseBlock(c *caddyfile.Dispenser, f *Forward) error {
|
||||
func parseBlock(c *caddy.Controller, f *Forward) error {
|
||||
switch c.Val() {
|
||||
case "except":
|
||||
ignore := c.RemainingArgs()
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// truncated looks at the error and if truncated return a nil error
|
||||
// truncated looks at the error and if truncated return a nil errror
|
||||
// and a possible reconstructed dns message if that was nil.
|
||||
func truncated(state request.Request, ret *dns.Msg, err error) (*dns.Msg, error) {
|
||||
// If you query for instance ANY isc.org; you get a truncated query back which miekg/dns fails to unpack
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ com net {
|
||||
erratic
|
||||
health :8080
|
||||
}
|
||||
~~~
|
||||
~~~~
|
||||
|
||||
## Plugins
|
||||
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ func setup(c *caddy.Controller) error {
|
||||
})
|
||||
|
||||
c.OnStartup(func() error {
|
||||
metrics.MustRegister(c, HealthDuration)
|
||||
once.Do(func() { metrics.MustRegister(c, HealthDuration) })
|
||||
return nil
|
||||
})
|
||||
|
||||
|
||||
+2
@@ -66,6 +66,8 @@ func (h Hosts) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (
|
||||
m.Authoritative, m.RecursionAvailable = true, true
|
||||
m.Answer = answers
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
||||
+7
-23
@@ -54,27 +54,11 @@ func newHostsMap() *hostsMap {
|
||||
}
|
||||
}
|
||||
|
||||
// Len returns the total number of addresses in the hostmap, this includes
|
||||
// V4/V6 and any reverse addresses.
|
||||
func (h *hostsMap) Len() int {
|
||||
l := 0
|
||||
for _, v4 := range h.byNameV4 {
|
||||
l += len(v4)
|
||||
}
|
||||
for _, v6 := range h.byNameV6 {
|
||||
l += len(v6)
|
||||
}
|
||||
for _, a := range h.byAddr {
|
||||
l += len(a)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Hostsfile contains known host entries.
|
||||
type Hostsfile struct {
|
||||
sync.RWMutex
|
||||
|
||||
// list of zones we are authoritative for
|
||||
// list of zones we are authoritive for
|
||||
Origins []string
|
||||
|
||||
// hosts maps for lookups
|
||||
@@ -106,17 +90,13 @@ func (h *Hostsfile) readHosts() {
|
||||
return
|
||||
}
|
||||
|
||||
newMap := h.parse(file, h.inline)
|
||||
log.Debugf("Parsed hosts file into %d entries", newMap.Len())
|
||||
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
h.parseReader(file)
|
||||
|
||||
h.hmap = newMap
|
||||
// Update the data cache.
|
||||
h.mtime = stat.ModTime()
|
||||
h.size = stat.Size()
|
||||
|
||||
h.Unlock()
|
||||
}
|
||||
|
||||
func (h *Hostsfile) initInline(inline []string) {
|
||||
@@ -129,6 +109,10 @@ func (h *Hostsfile) initInline(inline []string) {
|
||||
*h.hmap = *h.inline
|
||||
}
|
||||
|
||||
func (h *Hostsfile) parseReader(r io.Reader) {
|
||||
h.hmap = h.parse(r, h.inline)
|
||||
}
|
||||
|
||||
// Parse reads the hostsfile and populates the byName and byAddr maps.
|
||||
func (h *Hostsfile) parse(r io.Reader, override *hostsMap) *hostsMap {
|
||||
hmap := newHostsMap()
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@ package hosts
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -83,8 +83,8 @@ func hostsParse(c *caddy.Controller) (Hosts, error) {
|
||||
h.path = args[0]
|
||||
args = args[1:]
|
||||
|
||||
if !filepath.IsAbs(h.path) && config.Root != "" {
|
||||
h.path = filepath.Join(config.Root, h.path)
|
||||
if !path.IsAbs(h.path) && config.Root != "" {
|
||||
h.path = path.Join(config.Root, h.path)
|
||||
}
|
||||
s, err := os.Stat(h.path)
|
||||
if err != nil {
|
||||
|
||||
+6
-12
@@ -7,10 +7,9 @@
|
||||
## Description
|
||||
|
||||
By just using *log* you dump all queries (and parts for the reply) on standard output. Options exist
|
||||
to tweak the output a little. The date/time prefix on log lines is RFC3339 formatted with
|
||||
milliseconds.
|
||||
to tweak the output a little.
|
||||
|
||||
Note that for busy servers logging will incur a performance hit.
|
||||
Note that for busy servers this will incur a performance hit.
|
||||
|
||||
## Syntax
|
||||
|
||||
@@ -60,14 +59,15 @@ The following place holders are supported:
|
||||
* `{name}`: qname of the request
|
||||
* `{class}`: qclass of the request
|
||||
* `{proto}`: protocol used (tcp or udp)
|
||||
* `{when}`: time of the query
|
||||
* `{remote}`: client's IP address, for IPv6 addresses these are enclosed in brackets: `[::1]`
|
||||
* `{size}`: request size in bytes
|
||||
* `{port}`: client's port
|
||||
* `{duration}`: response duration
|
||||
* `{rcode}`: response RCODE
|
||||
* `{rsize}`: raw (uncompressed), response size (a client may receive a smaller response)
|
||||
* `{rsize}`: response size
|
||||
* `{>rflags}`: response flags, each set flag will be displayed, e.g. "aa, tc". This includes the qr
|
||||
bit as well
|
||||
bit as well.
|
||||
* `{>bufsize}`: the EDNS0 buffer size advertised in the query
|
||||
* `{>do}`: is the EDNS0 DO (DNSSEC OK) bit set in the query
|
||||
* `{>id}`: query ID
|
||||
@@ -76,15 +76,9 @@ The following place holders are supported:
|
||||
The default Common Log Format is:
|
||||
|
||||
~~~ txt
|
||||
`{remote}:{port} - {>id} "{type} {class} {name} {proto} {size} {>do} {>bufsize}" {rcode} {>rflags} {rsize} {duration}`
|
||||
`{remote}:{port} - [{when}] {>id} "{type} {class} {name} {proto} {size} {>do} {>bufsize}" {rcode} {>rflags} {rsize} {duration}`
|
||||
~~~
|
||||
|
||||
Each of these logs will be outputted with `log.Infof`, so a typical example looks like this:
|
||||
|
||||
~~~ txt
|
||||
2018-10-30T19:10:07.547Z [INFO] [::1]:50759 - 29008 "A IN example.org. udp 41 false 4096" NOERROR qr,rd,ra,ad 68 0.037990251s
|
||||
~~~~
|
||||
|
||||
## Examples
|
||||
|
||||
Log all requests to stdout
|
||||
|
||||
+4
-3
@@ -3,12 +3,12 @@ package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||
"github.com/coredns/coredns/plugin/pkg/rcode"
|
||||
"github.com/coredns/coredns/plugin/pkg/replacer"
|
||||
"github.com/coredns/coredns/plugin/pkg/response"
|
||||
@@ -58,7 +58,7 @@ func (l Logger) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
||||
// and we shouldn't have an empty rule.Class.
|
||||
if rule.Class[response.All] || rule.Class[class] {
|
||||
rep := replacer.New(r, rrw, CommonLogEmptyValue)
|
||||
clog.Infof(rep.Replace(rule.Format))
|
||||
rule.Log.Println(rep.Replace(rule.Format))
|
||||
}
|
||||
|
||||
return rc, err
|
||||
@@ -75,11 +75,12 @@ type Rule struct {
|
||||
NameScope string
|
||||
Class map[response.Class]bool
|
||||
Format string
|
||||
Log *log.Logger
|
||||
}
|
||||
|
||||
const (
|
||||
// CommonLogFormat is the common log format.
|
||||
CommonLogFormat = `{remote}:{port} ` + CommonLogEmptyValue + ` {>id} "{type} {class} {name} {proto} {size} {>do} {>bufsize}" {rcode} {>rflags} {rsize} {duration}`
|
||||
CommonLogFormat = `{remote}:{port} ` + CommonLogEmptyValue + ` [{when}] {>id} "{type} {class} {name} {proto} {size} {>do} {>bufsize}" {rcode} {>rflags} {rsize} {duration}`
|
||||
// CommonLogEmptyValue is the common empty log value.
|
||||
CommonLogEmptyValue = "-"
|
||||
// CombinedLogFormat is the combined log format.
|
||||
|
||||
+12
@@ -1,6 +1,9 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/pkg/response"
|
||||
@@ -22,6 +25,15 @@ func setup(c *caddy.Controller) error {
|
||||
return plugin.Error("log", err)
|
||||
}
|
||||
|
||||
// Open the log files for writing when the server starts
|
||||
c.OnStartup(func() error {
|
||||
for i := 0; i < len(rules); i++ {
|
||||
rules[i].Log = log.New(os.Stdout, "", 0)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
return Logger{Next: next, Rules: rules, ErrorFunc: dnsserver.DefaultErrorFunc}
|
||||
})
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ Use an alternative address:
|
||||
}
|
||||
~~~
|
||||
|
||||
Or via an environment variable (this is supported throughout the Corefile): `export PORT=9253`, and
|
||||
Or via an enviroment variable (this is supported throughout the Corefile): `export PORT=9253`, and
|
||||
then:
|
||||
|
||||
~~~ corefile
|
||||
|
||||
+14
-33
@@ -2,12 +2,10 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||
@@ -24,7 +22,6 @@ type Metrics struct {
|
||||
ln net.Listener
|
||||
lnSetup bool
|
||||
mux *http.ServeMux
|
||||
srv *http.Server
|
||||
|
||||
zoneNames []string
|
||||
zoneMap map[string]bool
|
||||
@@ -57,15 +54,7 @@ func New(addr string) *Metrics {
|
||||
}
|
||||
|
||||
// MustRegister wraps m.Reg.MustRegister.
|
||||
func (m *Metrics) MustRegister(c prometheus.Collector) {
|
||||
err := m.Reg.Register(c)
|
||||
if err != nil {
|
||||
// ignore any duplicate error, but fatal on any other kind of error
|
||||
if _, ok := err.(prometheus.AlreadyRegisteredError); !ok {
|
||||
log.Fatalf("Cannot register metrics collector: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
func (m *Metrics) MustRegister(c prometheus.Collector) { m.Reg.MustRegister(c) }
|
||||
|
||||
// AddZone adds zone z to m.
|
||||
func (m *Metrics) AddZone(z string) {
|
||||
@@ -105,9 +94,9 @@ func (m *Metrics) OnStartup() error {
|
||||
|
||||
m.mux = http.NewServeMux()
|
||||
m.mux.Handle("/metrics", promhttp.HandlerFor(m.Reg, promhttp.HandlerOpts{}))
|
||||
m.srv = &http.Server{Handler: m.mux}
|
||||
|
||||
go func() {
|
||||
m.srv.Serve(m.ln)
|
||||
http.Serve(m.ln, m.mux)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
@@ -117,28 +106,24 @@ func (m *Metrics) OnRestart() error {
|
||||
if !m.lnSetup {
|
||||
return nil
|
||||
}
|
||||
uniqAddr.Unset(m.Addr)
|
||||
return m.stopServer()
|
||||
}
|
||||
|
||||
func (m *Metrics) stopServer() error {
|
||||
if !m.lnSetup {
|
||||
return nil
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||
defer cancel()
|
||||
if err := m.srv.Shutdown(ctx); err != nil {
|
||||
log.Infof("Failed to stop prometheus http server: %s", err)
|
||||
return err
|
||||
}
|
||||
m.lnSetup = false
|
||||
uniqAddr.SetTodo(m.Addr)
|
||||
|
||||
m.ln.Close()
|
||||
m.lnSetup = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnFinalShutdown tears down the metrics listener on shutdown and restart.
|
||||
func (m *Metrics) OnFinalShutdown() error {
|
||||
return m.stopServer()
|
||||
// We allow prometheus statements in multiple Server Blocks, but only the first
|
||||
// will open the listener, for the rest they are all nil; guard against that.
|
||||
if !m.lnSetup {
|
||||
return nil
|
||||
}
|
||||
|
||||
m.lnSetup = false
|
||||
return m.ln.Close()
|
||||
}
|
||||
|
||||
func keys(m map[string]bool) []string {
|
||||
@@ -153,10 +138,6 @@ func keys(m map[string]bool) []string {
|
||||
// we listen on "localhost:0" and need to retrieve the actual address.
|
||||
var ListenAddr string
|
||||
|
||||
// shutdownTimeout is the maximum amount of time the metrics plugin will wait
|
||||
// before erroring when it tries to close the metrics server
|
||||
const shutdownTimeout time.Duration = time.Second * 5
|
||||
|
||||
var buildInfo = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Name: "build_info",
|
||||
|
||||
+4
-7
@@ -31,13 +31,6 @@ func setup(c *caddy.Controller) error {
|
||||
return plugin.Error("prometheus", err)
|
||||
}
|
||||
|
||||
// register the metrics to its address (ensure only one active metrics per address)
|
||||
obj := uniqAddr.Set(m.Addr, m.OnStartup, m)
|
||||
//propagate the real active Registry to current metrics
|
||||
if om, ok := obj.(*Metrics); ok {
|
||||
m.Reg = om.Reg
|
||||
}
|
||||
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
m.Next = next
|
||||
return m
|
||||
@@ -62,6 +55,10 @@ func setup(c *caddy.Controller) error {
|
||||
func prometheusParse(c *caddy.Controller) (*Metrics, error) {
|
||||
var met = New(defaultAddr)
|
||||
|
||||
defer func() {
|
||||
uniqAddr.Set(met.Addr, met.OnStartup)
|
||||
}()
|
||||
|
||||
i := 0
|
||||
for c.Next() {
|
||||
if i > 0 {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Report reports the metrics data associated with request.
|
||||
// Report reports the metrics data associcated with request.
|
||||
func Report(ctx context.Context, req request.Request, zone, rcode string, size int, start time.Time) {
|
||||
// Proto and Family.
|
||||
net := req.Proto()
|
||||
|
||||
+24
-6
@@ -6,7 +6,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -62,10 +61,22 @@ type (
|
||||
// Normalize will return the host portion of host, stripping
|
||||
// of any port or transport. The host will also be fully qualified and lowercased.
|
||||
func (h Host) Normalize() string {
|
||||
s := string(h)
|
||||
_, s = parse.Transport(s)
|
||||
|
||||
// The error can be ignore here, because this function is called after the corefile has already been vetted.
|
||||
s := string(h)
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(s, TransportTLS+"://"):
|
||||
s = s[len(TransportTLS+"://"):]
|
||||
case strings.HasPrefix(s, TransportDNS+"://"):
|
||||
s = s[len(TransportDNS+"://"):]
|
||||
case strings.HasPrefix(s, TransportGRPC+"://"):
|
||||
s = s[len(TransportGRPC+"://"):]
|
||||
case strings.HasPrefix(s, TransportHTTPS+"://"):
|
||||
s = s[len(TransportHTTPS+"://"):]
|
||||
}
|
||||
|
||||
// The error can be ignore here, because this function is called after the corefile
|
||||
// has already been vetted.
|
||||
host, _, _, _ := SplitHostPort(s)
|
||||
return Name(host).Normalize()
|
||||
}
|
||||
@@ -114,8 +125,7 @@ func SplitHostPort(s string) (host, port string, ipnet *net.IPNet, err error) {
|
||||
// Get the first lower octet boundary to see what encompassing zone we should be authoritative for.
|
||||
mod := (bits - ones) % sizeDigit
|
||||
nearest := (bits - ones) + mod
|
||||
offset := 0
|
||||
var end bool
|
||||
offset, end := 0, false
|
||||
for i := 0; i < nearest/sizeDigit; i++ {
|
||||
offset, end = dns.NextLabel(rev, offset)
|
||||
if end {
|
||||
@@ -127,3 +137,11 @@ func SplitHostPort(s string) (host, port string, ipnet *net.IPNet, err error) {
|
||||
}
|
||||
return host, port, n, nil
|
||||
}
|
||||
|
||||
// Duplicated from core/dnsserver/address.go !
|
||||
const (
|
||||
TransportDNS = "dns"
|
||||
TransportTLS = "tls"
|
||||
TransportGRPC = "grpc"
|
||||
TransportHTTPS = "https"
|
||||
)
|
||||
|
||||
+17
-19
@@ -9,10 +9,10 @@ import (
|
||||
)
|
||||
|
||||
// Hash returns the FNV hash of what.
|
||||
func Hash(what []byte) uint64 {
|
||||
h := fnv.New64()
|
||||
func Hash(what []byte) uint32 {
|
||||
h := fnv.New32()
|
||||
h.Write(what)
|
||||
return h.Sum64()
|
||||
return h.Sum32()
|
||||
}
|
||||
|
||||
// Cache is cache.
|
||||
@@ -22,7 +22,7 @@ type Cache struct {
|
||||
|
||||
// shard is a cache with random eviction.
|
||||
type shard struct {
|
||||
items map[uint64]interface{}
|
||||
items map[uint32]interface{}
|
||||
size int
|
||||
|
||||
sync.RWMutex
|
||||
@@ -31,8 +31,8 @@ type shard struct {
|
||||
// New returns a new cache.
|
||||
func New(size int) *Cache {
|
||||
ssize := size / shardSize
|
||||
if ssize < 4 {
|
||||
ssize = 4
|
||||
if ssize < 512 {
|
||||
ssize = 512
|
||||
}
|
||||
|
||||
c := &Cache{}
|
||||
@@ -45,19 +45,19 @@ func New(size int) *Cache {
|
||||
}
|
||||
|
||||
// Add adds a new element to the cache. If the element already exists it is overwritten.
|
||||
func (c *Cache) Add(key uint64, el interface{}) {
|
||||
func (c *Cache) Add(key uint32, el interface{}) {
|
||||
shard := key & (shardSize - 1)
|
||||
c.shards[shard].Add(key, el)
|
||||
}
|
||||
|
||||
// Get looks up element index under key.
|
||||
func (c *Cache) Get(key uint64) (interface{}, bool) {
|
||||
func (c *Cache) Get(key uint32) (interface{}, bool) {
|
||||
shard := key & (shardSize - 1)
|
||||
return c.shards[shard].Get(key)
|
||||
}
|
||||
|
||||
// Remove removes the element indexed with key.
|
||||
func (c *Cache) Remove(key uint64) {
|
||||
func (c *Cache) Remove(key uint32) {
|
||||
shard := key & (shardSize - 1)
|
||||
c.shards[shard].Remove(key)
|
||||
}
|
||||
@@ -72,10 +72,10 @@ func (c *Cache) Len() int {
|
||||
}
|
||||
|
||||
// newShard returns a new shard with size.
|
||||
func newShard(size int) *shard { return &shard{items: make(map[uint64]interface{}), size: size} }
|
||||
func newShard(size int) *shard { return &shard{items: make(map[uint32]interface{}), size: size} }
|
||||
|
||||
// Add adds element indexed by key into the cache. Any existing element is overwritten
|
||||
func (s *shard) Add(key uint64, el interface{}) {
|
||||
func (s *shard) Add(key uint32, el interface{}) {
|
||||
l := s.Len()
|
||||
if l+1 > s.size {
|
||||
s.Evict()
|
||||
@@ -87,7 +87,7 @@ func (s *shard) Add(key uint64, el interface{}) {
|
||||
}
|
||||
|
||||
// Remove removes the element indexed by key from the cache.
|
||||
func (s *shard) Remove(key uint64) {
|
||||
func (s *shard) Remove(key uint32) {
|
||||
s.Lock()
|
||||
delete(s.items, key)
|
||||
s.Unlock()
|
||||
@@ -95,28 +95,26 @@ func (s *shard) Remove(key uint64) {
|
||||
|
||||
// Evict removes a random element from the cache.
|
||||
func (s *shard) Evict() {
|
||||
hasKey := false
|
||||
var key uint64
|
||||
key := -1
|
||||
|
||||
s.RLock()
|
||||
for k := range s.items {
|
||||
key = k
|
||||
hasKey = true
|
||||
key = int(k)
|
||||
break
|
||||
}
|
||||
s.RUnlock()
|
||||
|
||||
if !hasKey {
|
||||
if key == -1 {
|
||||
// empty cache
|
||||
return
|
||||
}
|
||||
|
||||
// If this item is gone between the RUnlock and Lock race we don't care.
|
||||
s.Remove(key)
|
||||
s.Remove(uint32(key))
|
||||
}
|
||||
|
||||
// Get looks up the element indexed under key.
|
||||
func (s *shard) Get(key uint64) (interface{}, bool) {
|
||||
func (s *shard) Get(key uint32) (interface{}, bool) {
|
||||
s.RLock()
|
||||
el, found := s.items[key]
|
||||
s.RUnlock()
|
||||
|
||||
Generated
Vendored
+11
-27
@@ -1,25 +1,19 @@
|
||||
package parse
|
||||
package dnsutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// HostPortOrFile parses the strings in s, each string can either be a
|
||||
// address, [scheme://]address:port or a filename. The address part is checked
|
||||
// and in case of filename a resolv.conf like file is (assumed) and parsed and
|
||||
// the nameservers found are returned.
|
||||
func HostPortOrFile(s ...string) ([]string, error) {
|
||||
// ParseHostPortOrFile parses the strings in s, each string can either be a address,
|
||||
// address:port or a filename. The address part is checked and the filename case a
|
||||
// resolv.conf like file is parsed and the nameserver found are returned.
|
||||
func ParseHostPortOrFile(s ...string) ([]string, error) {
|
||||
var servers []string
|
||||
for _, h := range s {
|
||||
|
||||
trans, host := Transport(h)
|
||||
|
||||
for _, host := range s {
|
||||
addr, _, err := net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
// Parse didn't work, it is not a addr:port combo
|
||||
@@ -32,23 +26,13 @@ func HostPortOrFile(s ...string) ([]string, error) {
|
||||
}
|
||||
return servers, fmt.Errorf("not an IP address or file: %q", host)
|
||||
}
|
||||
var ss string
|
||||
switch trans {
|
||||
case transport.DNS:
|
||||
ss = net.JoinHostPort(host, transport.Port)
|
||||
case transport.TLS:
|
||||
ss = transport.TLS + "://" + net.JoinHostPort(host, transport.TLSPort)
|
||||
case transport.GRPC:
|
||||
ss = transport.GRPC + "://" + net.JoinHostPort(host, transport.GRPCPort)
|
||||
case transport.HTTPS:
|
||||
ss = transport.HTTPS + "://" + net.JoinHostPort(host, transport.HTTPSPort)
|
||||
}
|
||||
ss := net.JoinHostPort(host, "53")
|
||||
servers = append(servers, ss)
|
||||
continue
|
||||
}
|
||||
|
||||
if net.ParseIP(addr) == nil {
|
||||
// Not an IP address.
|
||||
// No an IP address.
|
||||
ss, err := tryFile(host)
|
||||
if err == nil {
|
||||
servers = append(servers, ss...)
|
||||
@@ -56,7 +40,7 @@ func HostPortOrFile(s ...string) ([]string, error) {
|
||||
}
|
||||
return servers, fmt.Errorf("not an IP address or file: %q", host)
|
||||
}
|
||||
servers = append(servers, h)
|
||||
servers = append(servers, host)
|
||||
}
|
||||
return servers, nil
|
||||
}
|
||||
@@ -77,9 +61,9 @@ func tryFile(s string) ([]string, error) {
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// HostPort will check if the host part is a valid IP address, if the
|
||||
// ParseHostPort will check if the host part is a valid IP address, if the
|
||||
// IP address is valid, but no port is found, defaultPort is added.
|
||||
func HostPort(s, defaultPort string) (string, error) {
|
||||
func ParseHostPort(s, defaultPort string) (string, error) {
|
||||
addr, port, err := net.SplitHostPort(s)
|
||||
if port == "" {
|
||||
port = defaultPort
|
||||
+5
-3
@@ -8,10 +8,12 @@ import (
|
||||
|
||||
// Join joins labels to form a fully qualified domain name. If the last label is
|
||||
// the root label it is ignored. Not other syntax checks are performed.
|
||||
func Join(labels ...string) string {
|
||||
func Join(labels []string) string {
|
||||
ll := len(labels)
|
||||
if labels[ll-1] == "." {
|
||||
return strings.Join(labels[:ll-1], ".") + "."
|
||||
s := strings.Join(labels[:ll-1], ".")
|
||||
return dns.Fqdn(s)
|
||||
}
|
||||
return dns.Fqdn(strings.Join(labels, "."))
|
||||
s := strings.Join(labels, ".")
|
||||
return dns.Fqdn(s)
|
||||
}
|
||||
|
||||
+29
-9
@@ -14,21 +14,34 @@ func MinimalTTL(m *dns.Msg, mt response.Type) time.Duration {
|
||||
return MinimalDefaultTTL
|
||||
}
|
||||
|
||||
// No records or OPT is the only record, return a short ttl as a fail safe.
|
||||
if len(m.Answer)+len(m.Ns) == 0 &&
|
||||
(len(m.Extra) == 0 || (len(m.Extra) == 1 && m.Extra[0].Header().Rrtype == dns.TypeOPT)) {
|
||||
// No data to examine, return a short ttl as a fail safe.
|
||||
if len(m.Answer)+len(m.Ns)+len(m.Extra) == 0 {
|
||||
return MinimalDefaultTTL
|
||||
}
|
||||
|
||||
minTTL := MaximumDefaulTTL
|
||||
for _, r := range m.Answer {
|
||||
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||
switch mt {
|
||||
case response.NameError, response.NoData:
|
||||
if r.Header().Rrtype == dns.TypeSOA {
|
||||
minTTL = time.Duration(r.(*dns.SOA).Minttl) * time.Second
|
||||
}
|
||||
case response.NoError, response.Delegation:
|
||||
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, r := range m.Ns {
|
||||
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||
switch mt {
|
||||
case response.NameError, response.NoData:
|
||||
if r.Header().Rrtype == dns.TypeSOA {
|
||||
minTTL = time.Duration(r.(*dns.SOA).Minttl) * time.Second
|
||||
}
|
||||
case response.NoError, response.Delegation:
|
||||
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +50,15 @@ func MinimalTTL(m *dns.Msg, mt response.Type) time.Duration {
|
||||
// OPT records use TTL field for extended rcode and flags
|
||||
continue
|
||||
}
|
||||
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||
switch mt {
|
||||
case response.NameError, response.NoData:
|
||||
if r.Header().Rrtype == dns.TypeSOA {
|
||||
minTTL = time.Duration(r.(*dns.SOA).Minttl) * time.Second
|
||||
}
|
||||
case response.NoError, response.Delegation:
|
||||
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||
}
|
||||
}
|
||||
}
|
||||
return minTTL
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ func NewRequest(method, url string, m *dns.Msg) (*http.Request, error) {
|
||||
|
||||
}
|
||||
|
||||
// ResponseToMsg converts a http.Response to a dns message.
|
||||
// ResponseToMsg converts a http.Repsonse to a dns message.
|
||||
func ResponseToMsg(resp *http.Response) (*dns.Msg, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
|
||||
+10
-29
@@ -1,36 +1,29 @@
|
||||
// Package log implements a small wrapper around the std lib log package.
|
||||
// It implements log levels by prefixing the logs with the current time
|
||||
// with in RFC3339Milli and [INFO], [DEBUG], [WARNING] or [ERROR].
|
||||
// It implements log levels by prefixing the logs with [INFO], [DEBUG],
|
||||
// [WARNING] or [ERROR].
|
||||
// Debug logging is available and enabled if the *debug* plugin is used.
|
||||
//
|
||||
// log.Info("this is some logging"), will log on the Info level.
|
||||
//
|
||||
// log.Debug("this is debug output"), will log in the Debug level, etc.
|
||||
// log.Debug("this is debug output"), will log in the Debug level.
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
golog "log"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// D controls whether we should output debug logs. If true, we do.
|
||||
var D bool
|
||||
|
||||
// RFC3339Milli doesn't exist, invent it here.
|
||||
func clock() string { return time.Now().Format("2006-01-02T15:04:05.999Z07:00") }
|
||||
|
||||
// logf calls log.Printf prefixed with level.
|
||||
func logf(level, format string, v ...interface{}) {
|
||||
golog.Print(clock(), level, fmt.Sprintf(format, v...))
|
||||
s := level + fmt.Sprintf(format, v...)
|
||||
golog.Print(s)
|
||||
}
|
||||
|
||||
// log calls log.Print prefixed with level.
|
||||
func log(level string, v ...interface{}) {
|
||||
golog.Print(clock(), level, fmt.Sprint(v...))
|
||||
}
|
||||
func log(level string, v ...interface{}) { s := level + fmt.Sprint(v...); golog.Print(s) }
|
||||
|
||||
// Debug is equivalent to log.Print(), but prefixed with "[DEBUG] ". It only outputs something
|
||||
// if D is true.
|
||||
@@ -68,21 +61,9 @@ func Error(v ...interface{}) { log(err, v...) }
|
||||
// Errorf is equivalent to log.Printf, but prefixed with "[ERROR] ".
|
||||
func Errorf(format string, v ...interface{}) { logf(err, format, v...) }
|
||||
|
||||
// Fatal is equivalent to log.Print, but prefixed with "[FATAL] ", and calling
|
||||
// os.Exit(1).
|
||||
func Fatal(v ...interface{}) { log(fatal, v...); os.Exit(1) }
|
||||
|
||||
// Fatalf is equivalent to log.Printf, but prefixed with "[FATAL] ", and calling
|
||||
// os.Exit(1)
|
||||
func Fatalf(format string, v ...interface{}) { logf(fatal, format, v...); os.Exit(1) }
|
||||
|
||||
// Discard sets the log output to /dev/null.
|
||||
func Discard() { golog.SetOutput(ioutil.Discard) }
|
||||
|
||||
const (
|
||||
debug = " [DEBUG] "
|
||||
err = " [ERROR] "
|
||||
fatal = " [FATAL] "
|
||||
info = " [INFO] "
|
||||
warning = " [WARNING] "
|
||||
debug = "[DEBUG] "
|
||||
err = "[ERROR] "
|
||||
warning = "[WARNING] "
|
||||
info = "[INFO] "
|
||||
)
|
||||
|
||||
-7
@@ -3,7 +3,6 @@ package log
|
||||
import (
|
||||
"fmt"
|
||||
golog "log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// P is a logger that includes the plugin doing the logging.
|
||||
@@ -59,10 +58,4 @@ func (p P) Error(v ...interface{}) { p.log(err, v...) }
|
||||
// Errorf logs as log.Errorf.
|
||||
func (p P) Errorf(format string, v ...interface{}) { p.logf(err, format, v...) }
|
||||
|
||||
// Fatal logs as log.Fatal and calls os.Exit(1).
|
||||
func (p P) Fatal(v ...interface{}) { p.log(fatal, v...); os.Exit(1) }
|
||||
|
||||
// Fatalf logs as log.Fatalf and calls os.Exit(1).
|
||||
func (p P) Fatalf(format string, v ...interface{}) { p.logf(fatal, format, v...); os.Exit(1) }
|
||||
|
||||
func pFormat(s string) string { return "plugin/" + s + ": " }
|
||||
|
||||
+3
-4
@@ -4,8 +4,7 @@ package parse
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/mholt/caddy"
|
||||
)
|
||||
|
||||
@@ -20,7 +19,7 @@ func Transfer(c *caddy.Controller, secondary bool) (tos, froms []string, err err
|
||||
tos = c.RemainingArgs()
|
||||
for i := range tos {
|
||||
if tos[i] != "*" {
|
||||
normalized, err := HostPort(tos[i], transport.Port)
|
||||
normalized, err := dnsutil.ParseHostPort(tos[i], "53")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -35,7 +34,7 @@ func Transfer(c *caddy.Controller, secondary bool) (tos, froms []string, err err
|
||||
froms = c.RemainingArgs()
|
||||
for i := range froms {
|
||||
if froms[i] != "*" {
|
||||
normalized, err := HostPort(froms[i], transport.Port)
|
||||
normalized, err := dnsutil.ParseHostPort(froms[i], "53")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user