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:
唐斌
2018-11-13 10:51:11 +08:00
147 changed files with 2067 additions and 4999 deletions
Generated
+16 -19
View File
@@ -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
View File
@@ -63,7 +63,7 @@
[[constraint]]
name = "github.com/coredns/coredns"
version = "1.2.6"
version = "v1.2.0"
[[constraint]]
name = "github.com/fatih/color"
+1 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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))
})
}
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
@@ -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)
}
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -39,7 +39,6 @@ var Directives = []string{
"auto",
"secondary",
"etcd",
"loop",
"forward",
"proxy",
"erratic",
+2 -2
View File
@@ -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
View File
@@ -2,7 +2,7 @@ package coremain
// Various CoreDNS constants.
const (
CoreVersion = "1.2.6"
CoreVersion = "1.2.0"
coreName = "CoreDNS"
serverType = "dns"
)
+22 -26
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -57,7 +57,7 @@ com net {
erratic
health :8080
}
~~~
~~~~
## Plugins
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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()
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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