slim
This commit is contained in:
commit
01979dc184
|
@ -21,8 +21,8 @@ integrationDefaults: &integrationDefaults
|
|||
image: ubuntu-1604:201903-01
|
||||
working_directory: ~/go/src/${CIRCLE_PROJECT_USERNAME}/coredns
|
||||
environment:
|
||||
- K8S_VERSION: v1.19.1
|
||||
- KIND_VERSION: v0.9.0
|
||||
- K8S_VERSION: v1.22.0
|
||||
- KIND_VERSION: v0.11.1
|
||||
- KUBECONFIG: /home/circleci/.kube/kind-config-kind
|
||||
|
||||
setupKubernetes: &setupKubernetes
|
||||
|
@ -56,7 +56,7 @@ jobs:
|
|||
name: Run Kubernetes tests
|
||||
command: |
|
||||
cd ~/go/src/${CIRCLE_PROJECT_USERNAME}/ci/test/kubernetes
|
||||
go mod download
|
||||
go mod tidy
|
||||
go test -v ./...
|
||||
|
||||
workflows:
|
||||
|
|
|
@ -9,3 +9,5 @@ aliases:
|
|||
/wai -> /label works as intended
|
||||
- |
|
||||
/release (.*) -> /exec /opt/bin/release-coredns $1
|
||||
- |
|
||||
/docker (.*) -> /exec /opt/bin/docker-coredns $1
|
||||
|
|
|
@ -5,3 +5,8 @@ updates:
|
|||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
|
|
@ -9,7 +9,7 @@ if [[ ! -f 'coredns.1.md' ]]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
for file in coredns.1.md corefile.5.md plugin/*/README.md; do
|
||||
for file in coredns.1.md corefile.5.md plugin/*/README.md man/*.1 man/*.5 man/*.7; do
|
||||
time=$(git log --pretty=format:%cd -n 1 --date='format:%Y%m%d%H%M.%S' "${file}")
|
||||
touch -m -t "${time}" "${file}"
|
||||
done
|
||||
|
|
|
@ -8,6 +8,8 @@ jobs:
|
|||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17.0'
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
@ -23,4 +25,4 @@ jobs:
|
|||
done
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v2.1.0
|
||||
|
|
|
@ -8,6 +8,8 @@ jobs:
|
|||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17.0'
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
@ -29,6 +31,8 @@ jobs:
|
|||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17.0'
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
@ -47,6 +51,8 @@ jobs:
|
|||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17.0'
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
@ -72,5 +78,8 @@ jobs:
|
|||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Test Makefile
|
||||
run: make DOCKER=bla GITHUB_ACCESS_TOKEN=bla -n build docker github-push docker-push -f Makefile.release
|
||||
- name: Test Makefile.release
|
||||
run: make GITHUB_ACCESS_TOKEN=x -n release github-push -f Makefile.release
|
||||
|
||||
- name: Test Makefile.docker
|
||||
run: make VERSION=x DOCKER=x -n release docker-push -f Makefile.docker
|
||||
|
|
|
@ -8,6 +8,12 @@ jobs:
|
|||
fix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17.0'
|
||||
id: go
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
|
|
@ -14,10 +14,12 @@ jobs:
|
|||
-
|
||||
name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17.0'
|
||||
-
|
||||
name: Update Docs
|
||||
run: |
|
||||
./.github/fixup_file_mtime.sh
|
||||
bash -x -e ./.github/fixup_file_mtime.sh
|
||||
make -f Makefile.doc
|
||||
-
|
||||
name: Set up Git
|
||||
|
@ -30,6 +32,7 @@ jobs:
|
|||
-
|
||||
name: Commit and push changes
|
||||
run: |
|
||||
set -x -e
|
||||
git add .
|
||||
if output=$(git status --porcelain) && [ ! -z "$output" ]; then
|
||||
git commit -s -m 'auto make -f Makefile.doc'
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
.github/CONTRIBUTING.md
|
|
@ -0,0 +1,96 @@
|
|||
# Makefile for creating and uploading CoreDNS docker image.
|
||||
#
|
||||
# First you should do a release and then call this Makefile to create and upload
|
||||
# the image.
|
||||
#
|
||||
# 1. Reuse the issue for this release
|
||||
# 2. In an issue give the command: /docker VERSION
|
||||
# Where VERSION is the version of the release.
|
||||
# 3. (to test as release /docker -t VERSION can be used.
|
||||
#
|
||||
# To release we run, these target from the this Makefile.docker ordered like:
|
||||
# * make release
|
||||
# * make docker-push
|
||||
#
|
||||
# Testing docker is done e.g. via:
|
||||
#
|
||||
# export DOCKER_PASSWORD=<pass>
|
||||
# export DOCKER_LOGIN=miek
|
||||
# make VERSION=x.y.z DOCKER=miek -f Makefile.docker release docker-push
|
||||
|
||||
ifeq (, $(shell which curl))
|
||||
$(error "No curl in $$PATH, please install")
|
||||
endif
|
||||
|
||||
# VERSION is the version we should download and use.
|
||||
VERSION:=
|
||||
# DOCKER is the docker image repo we need to push to.
|
||||
DOCKER:=
|
||||
NAME:=coredns
|
||||
GITHUB:=https://github.com/coredns/coredns/releases/download
|
||||
# mips is not in LINUX_ARCH because it's not supported by docker manifest. Keep this list in sync with the one in Makefile.release
|
||||
LINUX_ARCH:=amd64 arm arm64 mips64le ppc64le s390x
|
||||
DOCKER_IMAGE_NAME:=$(DOCKER)/$(NAME)
|
||||
DOCKER_IMAGE_LIST_VERSIONED:=$(shell echo $(LINUX_ARCH) | sed -e "s~[^ ]*~$(DOCKER_IMAGE_NAME)\-&:$(VERSION)~g")
|
||||
DOCKER_IMAGE_LIST_LATEST:=$(shell echo $(LINUX_ARCH) | sed -e "s~[^ ]*~$(DOCKER_IMAGE_NAME)\-&:latest~g")
|
||||
|
||||
all:
|
||||
@echo Use the 'release' target to download released binaries and build containers per arch, 'docker-push' to build and push a multi arch manifest.
|
||||
echo $(DOCKER_IMAGE_LIST_VERSIONED)
|
||||
echo $(DOCKER_IMAGE_LIST_LATEST)
|
||||
|
||||
release: image-download docker-build
|
||||
|
||||
.PHONY: image-download
|
||||
image-download:
|
||||
ifeq ($(VERSION),)
|
||||
$(error "Please specify a version use. Use VERSION=<version>")
|
||||
endif
|
||||
|
||||
@rm -rf build/docker
|
||||
@mkdir -p build/docker
|
||||
@# 1. Copy appropriate coredns binary to build/docker/<arch>
|
||||
@# 2. Copy Dockerfile into the correct dir as well.
|
||||
@# 3. Unpack the tgz from github into 'coredns' binary.
|
||||
for arch in $(LINUX_ARCH); do \
|
||||
mkdir build/docker/$${arch}; \
|
||||
curl -L $(GITHUB)/v$(VERSION)/coredns_$(VERSION)_linux_$${arch}.tgz > build/docker/$${arch}/coredns.tgz && \
|
||||
( cd build/docker/$${arch}; tar xf coredns.tgz && rm coredns.tgz ); \
|
||||
cp Dockerfile build/docker/$${arch} ; \
|
||||
done
|
||||
|
||||
.PHONY: docker-build
|
||||
docker-build:
|
||||
ifeq ($(DOCKER),)
|
||||
$(error "Please specify Docker registry to use. Use DOCKER=coredns for releases")
|
||||
else
|
||||
docker version
|
||||
for arch in $(LINUX_ARCH); do \
|
||||
docker build -t $(DOCKER_IMAGE_NAME)-$${arch}:$(VERSION) build/docker/$${arch} && \
|
||||
docker tag $(DOCKER_IMAGE_NAME)-$${arch}:$(VERSION) $(DOCKER_IMAGE_NAME)-$${arch}:latest ;\
|
||||
done
|
||||
endif
|
||||
|
||||
.PHONY: docker-push
|
||||
docker-push:
|
||||
ifeq ($(DOCKER),)
|
||||
$(error "Please specify Docker registry to use. Use DOCKER=coredns for releases")
|
||||
else
|
||||
@# Pushes coredns/coredns-$arch:$version images
|
||||
@# Creates manifest for multi-arch image
|
||||
@# Pushes multi-arch image to coredns/coredns:$version
|
||||
@echo $(DOCKER_PASSWORD) | docker login -u $(DOCKER_LOGIN) --password-stdin
|
||||
@echo Pushing: $(VERSION) to $(DOCKER_IMAGE_NAME)
|
||||
for arch in $(LINUX_ARCH); do \
|
||||
docker push $(DOCKER_IMAGE_NAME)-$${arch}:$(VERSION) ;\
|
||||
docker push $(DOCKER_IMAGE_NAME)-$${arch}:latest ;\
|
||||
done
|
||||
docker manifest create --amend $(DOCKER_IMAGE_NAME):$(VERSION) $(DOCKER_IMAGE_LIST_VERSIONED)
|
||||
docker manifest create --amend $(DOCKER_IMAGE_NAME):latest $(DOCKER_IMAGE_LIST_LATEST)
|
||||
for arch in $(LINUX_ARCH); do \
|
||||
docker manifest annotate --arch $${arch} $(DOCKER_IMAGE_NAME):$(VERSION) $(DOCKER_IMAGE_NAME)-$${arch}:$(VERSION) ;\
|
||||
docker manifest annotate --arch $${arch} $(DOCKER_IMAGE_NAME):latest $(DOCKER_IMAGE_NAME)-$${arch}:latest ;\
|
||||
done
|
||||
docker manifest push --purge $(DOCKER_IMAGE_NAME):$(VERSION)
|
||||
docker manifest push --purge $(DOCKER_IMAGE_NAME):latest
|
||||
endif
|
13
README.md
13
README.md
|
@ -1,8 +1,11 @@
|
|||
[![CoreDNS](https://coredns.io/images/CoreDNS_Colour_Horizontal.png)](https://coredns.io)
|
||||
|
||||
[![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/coredns/coredns)
|
||||
[![Build Status](https://img.shields.io/travis/coredns/coredns/master.svg?label=build)](https://travis-ci.org/coredns/coredns)
|
||||
[![fuzzit](https://app.fuzzit.dev/badge?org_id=coredns&branch=master)](https://fuzzit.dev)
|
||||
![CodeQL](https://github.com/coredns/coredns/actions/workflows/codeql-analysis.yml/badge.svg)
|
||||
![Go Fmt](https://github.com/coredns/coredns/actions/workflows/go.fmt.yml/badge.svg)
|
||||
![Go Tests](https://github.com/coredns/coredns/actions/workflows/go.test.yml/badge.svg)
|
||||
![Go Tidy](https://github.com/coredns/coredns/actions/workflows/go.tidy.yml/badge.svg)
|
||||
[![CircleCI](https://circleci.com/gh/coredns/coredns.svg?style=shield)](https://circleci.com/gh/coredns/coredns)
|
||||
[![Code Coverage](https://img.shields.io/codecov/c/github/coredns/coredns/master.svg)](https://codecov.io/github/coredns/coredns?branch=master)
|
||||
[![Docker Pulls](https://img.shields.io/docker/pulls/coredns/coredns.svg)](https://hub.docker.com/r/coredns/coredns)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/coredns/coredns)](https://goreportcard.com/report/coredns/coredns)
|
||||
|
@ -52,7 +55,7 @@ out-of-tree plugins.
|
|||
To compile CoreDNS, we assume you have a working Go setup. See various tutorials if you don’t have
|
||||
that already configured.
|
||||
|
||||
First, make sure your golang version is 1.12 or higher as `go mod` support is needed.
|
||||
First, make sure your golang version is 1.16 or higher as `go mod` support and other api is needed.
|
||||
See [here](https://github.com/golang/go/wiki/Modules) for `go mod` details.
|
||||
Then, check out the project and run `make` to compile the binary:
|
||||
|
||||
|
@ -70,7 +73,7 @@ CoreDNS requires Go to compile. However, if you already have docker installed an
|
|||
setup a Go environment, you could build CoreDNS easily:
|
||||
|
||||
```
|
||||
$ docker run --rm -i -t -v $PWD:/v -w /v golang:1.14 make
|
||||
$ docker run --rm -i -t -v $PWD:/v -w /v golang:1.16 make
|
||||
```
|
||||
|
||||
The above command alone will have `coredns` binary generated.
|
||||
|
@ -84,7 +87,7 @@ and starts listening on port 53 (override with `-dns.port`), it should show the
|
|||
~~~ txt
|
||||
.:53
|
||||
CoreDNS-1.6.6
|
||||
linux/amd64, go1.13.5, aa8c32
|
||||
linux/amd64, go1.16.10, aa8c32
|
||||
~~~
|
||||
|
||||
The following could be used to query the CoreDNS server that is running now:
|
||||
|
|
|
@ -50,6 +50,10 @@ type Config struct {
|
|||
// on them should register themselves here. The name should be the name as return by the
|
||||
// Handler's Name method.
|
||||
registry map[string]plugin.Handler
|
||||
|
||||
// firstConfigInBlock is used to reference the first config in a server block, for the
|
||||
// purpose of sharing single instance of each plugin among all zones in a server block.
|
||||
firstConfigInBlock *Config
|
||||
}
|
||||
|
||||
// keyForConfig builds a key for identifying the configs during setup time
|
||||
|
|
|
@ -21,6 +21,7 @@ const serverType = "dns"
|
|||
// wise they potentially clash with other server types.
|
||||
func init() {
|
||||
flag.StringVar(&Port, serverType+".port", DefaultPort, "Default port")
|
||||
flag.StringVar(&Port, "p", DefaultPort, "Default port")
|
||||
|
||||
caddy.RegisterServerType(serverType, caddy.ServerType{
|
||||
Directives: func() []string { return Directives },
|
||||
|
@ -96,6 +97,8 @@ func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddy
|
|||
|
||||
serverBlocks[ib].Keys = s.Keys // important to save back the new keys that are potentially created here.
|
||||
|
||||
var firstConfigInBlock *Config
|
||||
|
||||
for ik := range s.Keys {
|
||||
za := zoneAddrs[ik]
|
||||
s.Keys[ik] = za.String()
|
||||
|
@ -106,6 +109,15 @@ func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddy
|
|||
Port: za.Port,
|
||||
Transport: za.Transport,
|
||||
}
|
||||
|
||||
// Set reference to the first config in the current block.
|
||||
// This is used later by MakeServers to share a single plugin list
|
||||
// for all zones in a server block.
|
||||
if ik == 0 {
|
||||
firstConfigInBlock = cfg
|
||||
}
|
||||
cfg.firstConfigInBlock = firstConfigInBlock
|
||||
|
||||
keyConfig := keyForConfig(ib, ik)
|
||||
h.saveConfig(keyConfig, cfg)
|
||||
}
|
||||
|
@ -123,6 +135,17 @@ func (h *dnsContext) MakeServers() ([]caddy.Server, error) {
|
|||
return nil, errValid
|
||||
}
|
||||
|
||||
// Copy the Plugin, ListenHosts and Debug from first config in the block
|
||||
// to all other config in the same block . Doing this results in zones
|
||||
// sharing the same plugin instances and settings as other zones in
|
||||
// the same block.
|
||||
for _, c := range h.configs {
|
||||
c.Plugin = c.firstConfigInBlock.Plugin
|
||||
c.ListenHosts = c.firstConfigInBlock.ListenHosts
|
||||
c.Debug = c.firstConfigInBlock.Debug
|
||||
c.TLSConfig = c.firstConfigInBlock.TLSConfig
|
||||
}
|
||||
|
||||
// we must map (group) each config to a bind address
|
||||
groups, err := groupConfigsByListenAddr(h.configs)
|
||||
if err != nil {
|
||||
|
|
|
@ -12,10 +12,8 @@ import (
|
|||
|
||||
"coredns/caddy"
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/metrics/vars"
|
||||
"coredns/plugin/pkg/edns"
|
||||
"coredns/plugin/pkg/log"
|
||||
"coredns/plugin/pkg/rcode"
|
||||
"coredns/plugin/pkg/reuseport"
|
||||
"coredns/plugin/pkg/trace"
|
||||
"coredns/plugin/pkg/transport"
|
||||
|
@ -25,6 +23,23 @@ import (
|
|||
ot "github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
// WithServer returns the current server handling the request. It returns the
|
||||
// server listening address: <scheme>://[<bind>]:<port> Normally this is
|
||||
// something like "dns://:53", but if the bind plugin is used, i.e. "bind
|
||||
// 127.0.0.53", it will be "dns://127.0.0.53:53", etc. If not address is found
|
||||
// the empty string is returned.
|
||||
//
|
||||
// Basic usage with a metric:
|
||||
//
|
||||
// <metric>.WithLabelValues(metrics.WithServer(ctx), labels..).Add(1)
|
||||
func WithServer(ctx context.Context) string {
|
||||
srv := ctx.Value(Key{})
|
||||
if srv == nil {
|
||||
return ""
|
||||
}
|
||||
return srv.(*Server).Addr
|
||||
}
|
||||
|
||||
// Server represents an instance of a server, which serves
|
||||
// DNS requests at a particular address (host and port). A
|
||||
// server is capable of serving numerous zones on
|
||||
|
@ -214,8 +229,6 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
// need to make sure that we stay alive up here
|
||||
if rec := recover(); rec != nil {
|
||||
log.Errorf("Recovered from panic in server: %q", s.Addr)
|
||||
vars.Panic.Inc()
|
||||
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeServerFailure)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
@ -328,8 +341,6 @@ func errorAndMetricsFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int
|
|||
answer.SetRcode(r, rc)
|
||||
state.SizeAndDo(answer)
|
||||
|
||||
vars.Report(server, state, vars.Dropped, rcode.ToString(rc), answer.Len(), time.Now())
|
||||
|
||||
w.WriteMsg(answer)
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,11 @@ func NewServergRPC(addr string, group []*Config) (*ServergRPC, error) {
|
|||
// Should we error if some configs *don't* have TLS?
|
||||
tlsConfig = conf.TLSConfig
|
||||
}
|
||||
// http/2 is required when using gRPC. We need to specify it in next protos
|
||||
// or the upgrade won't happen.
|
||||
if tlsConfig != nil {
|
||||
tlsConfig.NextProtos = []string{"h2"}
|
||||
}
|
||||
|
||||
return &ServergRPC{Server: s, tlsConfig: tlsConfig}, nil
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ package dnsserver
|
|||
// care what plugin above them are doing.
|
||||
var Directives = []string{
|
||||
"metadata",
|
||||
"geoip",
|
||||
"cancel",
|
||||
"tls",
|
||||
"reload",
|
||||
|
@ -32,6 +33,7 @@ var Directives = []string{
|
|||
"loadbalance",
|
||||
"cache",
|
||||
"rewrite",
|
||||
"header",
|
||||
"dnssec",
|
||||
"autopath",
|
||||
"minimal",
|
||||
|
|
|
@ -4,7 +4,7 @@ package plugin
|
|||
|
||||
import (
|
||||
// Include all plugins.
|
||||
_ "coredns/plugin/acl"
|
||||
_ "coredns/caddy/onevent"
|
||||
_ "coredns/plugin/any"
|
||||
_ "coredns/plugin/auto"
|
||||
_ "coredns/plugin/autopath"
|
||||
|
@ -14,14 +14,16 @@ import (
|
|||
_ "coredns/plugin/cancel"
|
||||
_ "coredns/plugin/chaos"
|
||||
_ "coredns/plugin/debug"
|
||||
_ "coredns/plugin/dns64"
|
||||
_ "coredns/plugin/dnssec"
|
||||
_ "coredns/plugin/dnstap"
|
||||
_ "coredns/plugin/erratic"
|
||||
_ "coredns/plugin/errors"
|
||||
_ "coredns/plugin/file"
|
||||
_ "coredns/plugin/forward"
|
||||
_ "coredns/plugin/geoip"
|
||||
_ "coredns/plugin/grpc"
|
||||
_ "coredns/plugin/health"
|
||||
_ "coredns/plugin/header"
|
||||
_ "coredns/plugin/hosts"
|
||||
_ "coredns/plugin/loadbalance"
|
||||
_ "coredns/plugin/local"
|
||||
|
@ -37,9 +39,7 @@ import (
|
|||
_ "coredns/plugin/root"
|
||||
_ "coredns/plugin/secondary"
|
||||
_ "coredns/plugin/sign"
|
||||
_ "coredns/plugin/template"
|
||||
_ "coredns/plugin/tls"
|
||||
_ "coredns/plugin/transfer"
|
||||
_ "coredns/plugin/whoami"
|
||||
_ "coredns/caddy/onevent"
|
||||
)
|
||||
|
|
|
@ -24,7 +24,7 @@ Available options:
|
|||
: specify Corefile to load, if not given CoreDNS will look for a `Corefile` in the current
|
||||
directory.
|
||||
|
||||
**-dns.port** **PORT**
|
||||
**-dns.port** **PORT** or **-p** **PORT**
|
||||
: override default port (53) to listen on.
|
||||
|
||||
**-pidfile** **FILE**
|
||||
|
|
|
@ -4,7 +4,6 @@ package coremain
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
|
@ -96,7 +95,7 @@ func confLoader(serverType string) (caddy.Input, error) {
|
|||
return caddy.CaddyfileFromPipe(os.Stdin, serverType)
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadFile(conf)
|
||||
contents, err := os.ReadFile(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -109,7 +108,7 @@ func confLoader(serverType string) (caddy.Input, error) {
|
|||
|
||||
// defaultLoader loads the Corefile from the current working directory.
|
||||
func defaultLoader(serverType string) (caddy.Input, error) {
|
||||
contents, err := ioutil.ReadFile(caddy.DefaultConfigFile)
|
||||
contents, err := os.ReadFile(caddy.DefaultConfigFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
|
|
|
@ -5,7 +5,6 @@ package main
|
|||
import (
|
||||
"bufio"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -101,7 +100,7 @@ func formatAndWrite(file string, data string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(file, res, 0644); err != nil {
|
||||
if err = os.WriteFile(file, res, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
24
go.mod
24
go.mod
|
@ -4,26 +4,28 @@ go 1.16
|
|||
|
||||
require (
|
||||
github.com/apparentlymart/go-cidr v1.1.0
|
||||
github.com/coredns/caddy v1.1.1
|
||||
github.com/dnstap/golang-dnstap v0.4.0
|
||||
github.com/farsightsec/golang-framestream v0.3.0
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/go-cmp v0.5.6 // indirect
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645
|
||||
github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1
|
||||
github.com/miekg/dns v1.1.42
|
||||
github.com/miekg/dns v1.1.43
|
||||
github.com/opentracing/opentracing-go v1.2.0
|
||||
github.com/prometheus/client_golang v1.10.0
|
||||
github.com/oschwald/geoip2-golang v1.5.0
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
github.com/prometheus/common v0.24.0
|
||||
github.com/stretchr/testify v1.6.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
|
||||
golang.org/x/text v0.3.4 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/grpc v1.37.1
|
||||
github.com/prometheus/common v0.32.1
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf // indirect
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c // indirect
|
||||
google.golang.org/grpc v1.42.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
|
||||
replace github.com/coreos/bbolt => go.etcd.io/bbolt v1.3.4
|
||||
|
|
529
go.sum
529
go.sum
|
@ -1,91 +1,114 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
|
||||
github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0=
|
||||
github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dnstap/golang-dnstap v0.4.0 h1:KRHBoURygdGtBjDI2w4HifJfMAhhOqDuktAokaSa234=
|
||||
github.com/dnstap/golang-dnstap v0.4.0/go.mod h1:FqsSdH58NAmkAvKcpyxht7i4FoBjKu8E4JUPt8ipSUs=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/farsightsec/golang-framestream v0.3.0 h1:/spFQHucTle/ZIPkYqrfshQqPe2VQEzesH243TjIwqA=
|
||||
github.com/farsightsec/golang-framestream v0.3.0/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
|
@ -97,69 +120,49 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
|||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9 h1:w66aaP3c6SIQ0pi3QH1Tb4AMO3aWoEPxd1CNvLphbkA=
|
||||
github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9/go.mod h1:BaIJzjD2ZnHmx2acPF6XfGLPzNCMiBbMRqJr+8/8uRI=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
@ -167,268 +170,334 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
|
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY=
|
||||
github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
|
||||
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
|
||||
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
|
||||
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg=
|
||||
github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
|
||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.24.0 h1:aIycr3wRFxPUq8XlLQlGQ9aNXV3dFi5y62pe/SB262k=
|
||||
github.com/prometheus/common v0.24.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ=
|
||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c h1:FqrtZMB5Wr+/RecOM3uPJNPfWR8Upb5hAPnt7PU6i4k=
|
||||
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.37.1 h1:ARnQJNWxGyYJpdf/JXscNlQr/uv607ZPU9Z7ogHi+iI=
|
||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -437,32 +506,34 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
|||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
.\" Generated by Mmark Markdown Processer - mmark.miek.nl
|
||||
.TH "COREDNS-GEOIP" 7 "July 2021" "CoreDNS" "CoreDNS Plugins"
|
||||
|
||||
.SH "NAME"
|
||||
.PP
|
||||
\fIgeoip\fP - Lookup maxmind geoip2 databases using the client IP, then add associated geoip data to the context request.
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
The \fIgeoip\fP plugin add geo location data associated with the client IP, it allows you to configure a geoIP2 maxmind database
|
||||
\[la]https://dev.maxmind.com/geoip/docs/databases\[ra] to add the geo location data associated with the IP address.
|
||||
|
||||
.PP
|
||||
The data is added leveraging the \fImetadata\fP plugin, values can then be retrieved using it as well, for example:
|
||||
|
||||
.PP
|
||||
.RS
|
||||
|
||||
.nf
|
||||
import (
|
||||
"strconv"
|
||||
"github.com/coredns/coredns/plugin/metadata"
|
||||
)
|
||||
// ...
|
||||
if getLongitude := metadata.ValueFunc(ctx, "geoip/longitude"); getLongitude != nil {
|
||||
if longitude, err := strconv.ParseFloat(getLongitude(), 64); err == nil {
|
||||
// Do something useful with longitude.
|
||||
}
|
||||
} else {
|
||||
// The metadata label geoip/longitude for some reason, was not set.
|
||||
}
|
||||
// ...
|
||||
|
||||
.fi
|
||||
.RE
|
||||
|
||||
.SH "DATABASES"
|
||||
.PP
|
||||
The supported databases use city schema such as \fB\fCCity\fR and \fB\fCEnterprise\fR. Other databases types with different schemas are not supported yet.
|
||||
|
||||
.PP
|
||||
You can download a free and public City database
|
||||
\[la]https://dev.maxmind.com/geoip/geolite2-free-geolocation-data\[ra].
|
||||
|
||||
.SH "SYNTAX"
|
||||
.PP
|
||||
.RS
|
||||
|
||||
.nf
|
||||
geoip [DBFILE]
|
||||
|
||||
.fi
|
||||
.RE
|
||||
|
||||
.IP \(bu 4
|
||||
\fBDBFILE\fP the mmdb database file path.
|
||||
|
||||
|
||||
.SH "EXAMPLES"
|
||||
.PP
|
||||
The following configuration configures the \fB\fCCity\fR database.
|
||||
|
||||
.PP
|
||||
.RS
|
||||
|
||||
.nf
|
||||
\&. {
|
||||
geoip /opt/geoip2/db/GeoLite2\-City.mmdb
|
||||
metadata # Note that metadata plugin must be enabled as well.
|
||||
}
|
||||
|
||||
.fi
|
||||
.RE
|
||||
|
||||
.SH "METADATADA LABELS"
|
||||
.PP
|
||||
A limited set of fields will be exported as labels, all values are stored using strings \fBregardless of their underlying value type\fP, and therefore you may have to convert it back to its original type, note that numeric values are always represented in base 10.
|
||||
|
||||
.RS
|
||||
.TS
|
||||
allbox;
|
||||
l l l l
|
||||
l l l l .
|
||||
\fBLabel\fP\fB Type\fP\fB Example\fP\fB Description\fP
|
||||
\fB\fCgeoip/city/name\fR \fB\fCstring\fR \fB\fCCambridge\fR Then city name in English language.
|
||||
\fB\fCgeoip/country/code\fR \fB\fCstring\fR \fB\fCGB\fR Country ISO 3166-1
|
||||
\[la]https://en.wikipedia.org/wiki/ISO_3166-1\[ra] code.
|
||||
\fB\fCgeoip/country/name\fR \fB\fCstring\fR \fB\fCUnited Kingdom\fR The country name in English language.
|
||||
\fB\fCgeoip/country/is_in_european_union\fR \fB\fCbool\fR \fB\fCfalse\fR Either \fB\fCtrue\fR or \fB\fCfalse\fR.
|
||||
\fB\fCgeoip/continent/code\fR \fB\fCstring\fR \fB\fCEU\fR See Continent codes
|
||||
\[la]#ContinentCodes\[ra].
|
||||
\fB\fCgeoip/continent/name\fR \fB\fCstring\fR \fB\fCEurope\fR The continent name in English language.
|
||||
\fB\fCgeoip/latitude\fR \fB\fCfloat64\fR \fB\fC52.2242\fR Base 10, max available precision.
|
||||
\fB\fCgeoip/longitude\fR \fB\fCfloat64\fR \fB\fC0.1315\fR Base 10, max available precision.
|
||||
\fB\fCgeoip/timezone\fR \fB\fCstring\fR \fB\fCEurope/London\fR The timezone.
|
||||
\fB\fCgeoip/postalcode\fR \fB\fCstring\fR \fB\fCCB4\fR The postal code.
|
||||
.TE
|
||||
.RE
|
||||
|
||||
|
||||
.SH "CONTINENT CODES"
|
||||
.RS
|
||||
.TS
|
||||
allbox;
|
||||
l l
|
||||
l l .
|
||||
\fBValue\fP\fB Continent (EN)\fP
|
||||
AF Africa
|
||||
AN Antarctica
|
||||
AS Asia
|
||||
EU Europe
|
||||
NA North America
|
||||
OC Oceania
|
||||
SA South America
|
||||
.TE
|
||||
.RE
|
||||
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
.\" Generated by Mmark Markdown Processer - mmark.miek.nl
|
||||
.TH "COREDNS-HEADER" 7 "July 2021" "CoreDNS" "CoreDNS Plugins"
|
||||
|
||||
.SH "NAME"
|
||||
.PP
|
||||
\fIheader\fP - modifies the header for responses.
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fIheader\fP ensures that the flags are in the desired state for responses. The modifications are made transparently for
|
||||
the client.
|
||||
|
||||
.SH "SYNTAX"
|
||||
.PP
|
||||
.RS
|
||||
|
||||
.nf
|
||||
header {
|
||||
ACTION FLAGS...
|
||||
ACTION FLAGS...
|
||||
}
|
||||
|
||||
.fi
|
||||
.RE
|
||||
|
||||
.IP \(bu 4
|
||||
\fBACTION\fP defines the state for DNS message header flags. Actions are evaluated in the order they are defined so last one has the
|
||||
most precedence. Allowed values are:
|
||||
|
||||
.RS
|
||||
.IP \(en 4
|
||||
\fB\fCset\fR
|
||||
.IP \(en 4
|
||||
\fB\fCclear\fR
|
||||
|
||||
.RE
|
||||
.IP \(bu 4
|
||||
\fBFLAGS\fP are the DNS header flags that will be modified. Current supported flags include:
|
||||
|
||||
.RS
|
||||
.IP \(en 4
|
||||
\fB\fCaa\fR - Authoritative(Answer)
|
||||
.IP \(en 4
|
||||
\fB\fCra\fR - RecursionAvailable
|
||||
.IP \(en 4
|
||||
\fB\fCrd\fR - RecursionDesired
|
||||
|
||||
.RE
|
||||
|
||||
|
||||
.SH "EXAMPLES"
|
||||
.PP
|
||||
Make sure recursive available \fB\fCra\fR flag is set in all the responses:
|
||||
|
||||
.PP
|
||||
.RS
|
||||
|
||||
.nf
|
||||
\&. {
|
||||
header {
|
||||
set ra
|
||||
}
|
||||
}
|
||||
|
||||
.fi
|
||||
.RE
|
||||
|
||||
.PP
|
||||
Make sure "recursion available" \fB\fCra\fR and "authoritative answer" \fB\fCaa\fR flags are set and "recursion desired" is cleared in all responses:
|
||||
|
||||
.PP
|
||||
.RS
|
||||
|
||||
.nf
|
||||
\&. {
|
||||
header {
|
||||
set ra aa
|
||||
clear rd
|
||||
}
|
||||
}
|
||||
|
||||
.fi
|
||||
.RE
|
||||
|
|
@ -14,7 +14,7 @@ If you are running 1.7.1 you want to upgrade for the *cache* plugin fixes.
|
|||
|
||||
This release also adds three backwards incompatible changes. This will only affect you if you have an
|
||||
**external plugin** or use **outgoing zone transfers**. If you're using `dnstap` in your plugin,
|
||||
you'll need to upgrade to the new API as detailed in it's [documentation](/plugin/dnstap).
|
||||
you'll need to upgrade to the new API as detailed in it's [documentation](/plugins/dnstap).
|
||||
|
||||
Two, because Caddy is now developing a version 2 and we are using version 1, we've internalized
|
||||
Caddy into <https://github.com/coredns/caddy>. This means the `caddy` types change and *all* plugins
|
||||
|
|
|
@ -3,13 +3,17 @@ title = "CoreDNS-1.8.4 Release"
|
|||
description = "CoreDNS-1.8.4 Release Notes."
|
||||
tags = ["Release", "1.8.4", "Notes"]
|
||||
release = "1.8.4"
|
||||
date = 2021-05-14T07:00:00+00:00
|
||||
date = 2021-05-28T07:00:00+00:00
|
||||
author = "coredns"
|
||||
+++
|
||||
|
||||
The CoreDNS team has released
|
||||
[CoreDNS-1.8.4](https://github.com/coredns/coredns/releases/tag/v1.8.4). This release includes a
|
||||
bunch of bugfixes and a few enhancements, and a new (small) plugin called *minimal*.
|
||||
bunch of bugfixes and a few enhancements mostly in the *dnssec* and *kubernetes* plugins, and a new
|
||||
(small) plugin called *minimal*.
|
||||
|
||||
It also include a fix when using the "reverse zone cidr syntax", e.g. 10.0.0.0/15, now return the proper
|
||||
set of reverse zones.
|
||||
|
||||
## Brought to You By
|
||||
|
||||
|
@ -33,14 +37,17 @@ Yury Tsarev.
|
|||
## Noteworthy Changes
|
||||
|
||||
* core: fix reverse zones expansion (https://github.com/coredns/coredns/pull/4538)
|
||||
* plugins: fix Normalize (https://github.com/coredns/coredns/pull/4621)
|
||||
* reverse zone: make Normalize return proper reverse zones (https://github.com/coredns/coredns/pull/4621)
|
||||
* plugin/bind: Bind by interface name (https://github.com/coredns/coredns/pull/4522)
|
||||
* plugin/bind: Exclude interface or ip address (https://github.com/coredns/coredns/pull/4543)
|
||||
* plugin/dnssec: heck for two days of remaining validity (https://github.com/coredns/coredns/pull/4606)
|
||||
* plugin/dnssec: Check for two days of remaining validity (https://github.com/coredns/coredns/pull/4606)
|
||||
* plugin/dnssec: interface type correction for `periodicClean` sig validity check (https://github.com/coredns/coredns/pull/4608)
|
||||
* plugin/dnssec: use entire RRset as key input (https://github.com/coredns/coredns/pull/4537)
|
||||
* plugin/etcd: Bump etcd to v3.5.0-beta.3 (https://github.com/coredns/coredns/pull/4638)
|
||||
* plugin/forward: Add upstream metadata (https://github.com/coredns/coredns/pull/4521)
|
||||
* plugin/health: add logging for local health request (https://github.com/coredns/coredns/pull/4533)
|
||||
* plugin/health: add logging for local health request (https://github.com/coredns/coredns/pull/4533)
|
||||
* plugin/kubernetes: consider nil ready as ready (https://github.com/coredns/coredns/pull/4632)
|
||||
* plugin/kubernetes: do endpoint/slice check in retry loop (https://github.com/coredns/coredns/pull/4492)
|
||||
* plugin/kubernetes: Exclude unready endpoints from endpointslices (https://github.com/coredns/coredns/pull/4580)
|
||||
* plugin/metrics: remove RR type (https://github.com/coredns/coredns/pull/4534)
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
+++
|
||||
title = "CoreDNS-1.8.5 Release"
|
||||
description = "CoreDNS-1.8.5 Release Notes."
|
||||
tags = ["Release", "1.8.5", "Notes"]
|
||||
release = "1.8.5"
|
||||
date = 2021-09-10T07:00:00+00:00
|
||||
author = "coredns"
|
||||
+++
|
||||
|
||||
This is a rather big release, we now [share plugins among zones in the same server
|
||||
block](https://github.com/coredns/coredns/pull/4593), which should save memory. Various bug fixes in
|
||||
a bunch of plugins and not one, but two new plugins. A *geoip* plugin that can report **where** the
|
||||
query came from and a *header* plugin that allows you to fiddle with (some of) the header bits in a
|
||||
DNS message.
|
||||
|
||||
With this release, the `coredns_cache_misses_total` metric is deprecated. It will be removed in a later release.
|
||||
Users should migrate their promQL to use `coredns_cache_requests_total - coredns_cache_hits_total`.
|
||||
|
||||
## Brought to You By
|
||||
|
||||
Ben Kochie,
|
||||
Chris O'Haver,
|
||||
Jeongwook Park,
|
||||
Kohei Yoshida,
|
||||
Licht Takeuchi,
|
||||
Manuel Rüger,
|
||||
Mat Lowery,
|
||||
mfleader,
|
||||
Miek Gieben,
|
||||
Ondřej Benkovský,
|
||||
Qasim Sarfraz,
|
||||
rouzier,
|
||||
Sascha Grunert,
|
||||
Sven Nebel,
|
||||
Yong Tang.
|
||||
|
||||
## Noteworthy Changes
|
||||
|
||||
* core: Add -p for port flag (https://github.com/coredns/coredns/pull/4653)
|
||||
* core: Fix IPv6 case for CIDR format reverse zones (https://github.com/coredns/coredns/pull/4652)
|
||||
* core: Share plugins among zones in the same server block (https://github.com/coredns/coredns/pull/4593)
|
||||
* core: Upstream lookups are done with original EDNS options (https://github.com/coredns/coredns/pull/4826)
|
||||
* plugin/cache: Unset AD flag when DO is not set for cache miss (https://github.com/coredns/coredns/pull/4736)
|
||||
* plugin/cache: Update cache metrics and add a total cache request counter to follow Prometheus convention (https://github.com/coredns/coredns/pull/4781)
|
||||
* plugin/errors: Add configurable log level to errors plugin (https://github.com/coredns/coredns/pull/4718)
|
||||
* plugin/file: fix wildcard CNAME answer (https://github.com/coredns/coredns/pull/4828)
|
||||
* plugin/forward: Add proxy address as tag (https://github.com/coredns/coredns/pull/4757)
|
||||
* plugin/geoip: Create geoip plugin (https://github.com/coredns/coredns/pull/4688)
|
||||
* plugin/header: Introduce header plugin (https://github.com/coredns/coredns/pull/4752)
|
||||
* plugin/kubernetes: Add NS+hosts records to xfr response. Add coredns service to test data. (https://github.com/coredns/coredns/pull/4696)
|
||||
* plugin/kubernetes: Improve namespace usage (https://github.com/coredns/coredns/pull/4767)
|
||||
* plugins/kubernetes: Switch to klog/v2 (https://github.com/coredns/coredns/pull/4778)
|
||||
* plugin/kubernetes: Only answer transfer requests for authoritative zones (https://github.com/coredns/coredns/pull/4802)
|
||||
* plugin/log: Do not log NOERROR in log plugin when response is not available (https://github.com/coredns/coredns/pull/4725)
|
||||
* plugin/log: Fix closing of codeblock (https://github.com/coredns/coredns/pull/4680)
|
||||
* plugin/metrics: When no response is written, fallback to status of next plugin in prometheus plugin (https://github.com/coredns/coredns/pull/4727)
|
||||
* plugin/route53: Fix Route53 plugin cannot retrieve ECS Task Role (https://github.com/coredns/coredns/pull/4669)
|
||||
* plugin/secondary: Doc updates (https://github.com/coredns/coredns/pull/4686)
|
||||
* plugin/secondary: Retry initial transfer until successful (https://github.com/coredns/coredns/pull/4663)
|
||||
* plugin/trace: Fix rcode tag in case of no response (https://github.com/coredns/coredns/pull/4742)
|
||||
* plugin/trace: Publish trace id as metadata from trace plugin (https://github.com/coredns/coredns/pull/4749)
|
||||
* plugin/trace: Trace plugin can mark traces with error tag (https://github.com/coredns/coredns/pull/4720)
|
|
@ -0,0 +1,20 @@
|
|||
+++
|
||||
title = "CoreDNS-1.8.6 Release"
|
||||
description = "CoreDNS-1.8.6 Release Notes."
|
||||
tags = ["Release", "1.8.6", "Notes"]
|
||||
release = "1.8.6"
|
||||
date = "2021-10-07T00:00:00+00:00"
|
||||
author = "coredns"
|
||||
+++
|
||||
|
||||
This is a small bug fix release.
|
||||
|
||||
## Brought to You By
|
||||
|
||||
Chris O'Haver,
|
||||
Miek Gieben.
|
||||
|
||||
## Noteworthy Changes
|
||||
|
||||
* plugin/kubernetes: fix reload panic (https://github.com/coredns/coredns/pull/4881)
|
||||
* plugin/kubernetes: Don't use pod names longer than 63 characters as dns labels (https://github.com/coredns/coredns/pull/4908)
|
|
@ -20,6 +20,7 @@
|
|||
# log:log
|
||||
|
||||
metadata:metadata
|
||||
geoip:geoip
|
||||
cancel:cancel
|
||||
tls:tls
|
||||
reload:reload
|
||||
|
@ -41,6 +42,7 @@ chaos:chaos
|
|||
loadbalance:loadbalance
|
||||
cache:cache
|
||||
rewrite:rewrite
|
||||
header:header
|
||||
dnssec:dnssec
|
||||
autopath:autopath
|
||||
minimal:minimal
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
# acl
|
||||
|
||||
## Name
|
||||
|
||||
*acl* - enforces access control policies on source ip and prevents unauthorized access to DNS servers.
|
||||
|
||||
## Description
|
||||
|
||||
With `acl` enabled, users are able to block or filter suspicious DNS queries by configuring IP filter rule sets, i.e. allowing authorized queries to recurse or blocking unauthorized queries.
|
||||
|
||||
This plugin can be used multiple times per Server Block.
|
||||
|
||||
## Syntax
|
||||
|
||||
```
|
||||
acl [ZONES...] {
|
||||
ACTION [type QTYPE...] [net SOURCE...]
|
||||
}
|
||||
```
|
||||
|
||||
- **ZONES** zones it should be authoritative for. If empty, the zones from the configuration block are used.
|
||||
- **ACTION** (*allow*, *block*, or *filter*) defines the way to deal with DNS queries matched by this rule. The default action is *allow*, which means a DNS query not matched by any rules will be allowed to recurse. The difference between *block* and *filter* is that block returns status code of *REFUSED* while filter returns an empty set *NOERROR*
|
||||
- **QTYPE** is the query type to match for the requests to be allowed or blocked. Common resource record types are supported. `*` stands for all record types. The default behavior for an omitted `type QTYPE...` is to match all kinds of DNS queries (same as `type *`).
|
||||
- **SOURCE** is the source IP address to match for the requests to be allowed or blocked. Typical CIDR notation and single IP address are supported. `*` stands for all possible source IP addresses.
|
||||
|
||||
## Examples
|
||||
|
||||
To demonstrate the usage of plugin acl, here we provide some typical examples.
|
||||
|
||||
Block all DNS queries with record type A from 192.168.0.0/16:
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
acl {
|
||||
block type A net 192.168.0.0/16
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Filter all DNS queries with record type A from 192.168.0.0/16:
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
acl {
|
||||
filter type A net 192.168.0.0/16
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Block all DNS queries from 192.168.0.0/16 except for 192.168.1.0/24:
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
acl {
|
||||
allow net 192.168.1.0/24
|
||||
block net 192.168.0.0/16
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Allow only DNS queries from 192.168.0.0/24 and 192.168.1.0/24:
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
acl {
|
||||
allow net 192.168.0.0/24 192.168.1.0/24
|
||||
block
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Block all DNS queries from 192.168.1.0/24 towards a.example.org:
|
||||
|
||||
~~~ corefile
|
||||
example.org {
|
||||
acl a.example.org {
|
||||
block net 192.168.1.0/24
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
## Metrics
|
||||
|
||||
If monitoring is enabled (via the _prometheus_ plugin) then the following metrics are exported:
|
||||
|
||||
- `coredns_acl_blocked_requests_total{server, zone}` - counter of DNS requests being blocked.
|
||||
|
||||
- `coredns_acl_allowed_requests_total{server}` - counter of DNS requests being allowed.
|
||||
|
||||
The `server` and `zone` labels are explained in the _metrics_ plugin documentation.
|
|
@ -1,123 +0,0 @@
|
|||
package acl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/metrics"
|
||||
"coredns/request"
|
||||
|
||||
"github.com/infobloxopen/go-trees/iptree"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// ACL enforces access control policies on DNS queries.
|
||||
type ACL struct {
|
||||
Next plugin.Handler
|
||||
|
||||
Rules []rule
|
||||
}
|
||||
|
||||
// rule defines a list of Zones and some ACL policies which will be
|
||||
// enforced on them.
|
||||
type rule struct {
|
||||
zones []string
|
||||
policies []policy
|
||||
}
|
||||
|
||||
// action defines the action against queries.
|
||||
type action int
|
||||
|
||||
// policy defines the ACL policy for DNS queries.
|
||||
// A policy performs the specified action (block/allow) on all DNS queries
|
||||
// matched by source IP or QTYPE.
|
||||
type policy struct {
|
||||
action action
|
||||
qtypes map[uint16]struct{}
|
||||
filter *iptree.Tree
|
||||
}
|
||||
|
||||
const (
|
||||
// actionNone does nothing on the queries.
|
||||
actionNone = iota
|
||||
// actionAllow allows authorized queries to recurse.
|
||||
actionAllow
|
||||
// actionBlock blocks unauthorized queries towards protected DNS zones.
|
||||
actionBlock
|
||||
// actionFilter returns empty sets for queries towards protected DNS zones.
|
||||
actionFilter
|
||||
)
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (a ACL) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
state := request.Request{W: w, Req: r}
|
||||
|
||||
RulesCheckLoop:
|
||||
for _, rule := range a.Rules {
|
||||
// check zone.
|
||||
zone := plugin.Zones(rule.zones).Matches(state.Name())
|
||||
if zone == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
action := matchWithPolicies(rule.policies, w, r)
|
||||
switch action {
|
||||
case actionBlock:
|
||||
{
|
||||
m := new(dns.Msg)
|
||||
m.SetRcode(r, dns.RcodeRefused)
|
||||
w.WriteMsg(m)
|
||||
RequestBlockCount.WithLabelValues(metrics.WithServer(ctx), zone).Inc()
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
case actionAllow:
|
||||
{
|
||||
break RulesCheckLoop
|
||||
}
|
||||
case actionFilter:
|
||||
{
|
||||
m := new(dns.Msg)
|
||||
m.SetRcode(r, dns.RcodeSuccess)
|
||||
w.WriteMsg(m)
|
||||
RequestFilterCount.WithLabelValues(metrics.WithServer(ctx), zone).Inc()
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RequestAllowCount.WithLabelValues(metrics.WithServer(ctx)).Inc()
|
||||
return plugin.NextOrFailure(state.Name(), a.Next, ctx, w, r)
|
||||
}
|
||||
|
||||
// matchWithPolicies matches the DNS query with a list of ACL polices and returns suitable
|
||||
// action against the query.
|
||||
func matchWithPolicies(policies []policy, w dns.ResponseWriter, r *dns.Msg) action {
|
||||
state := request.Request{W: w, Req: r}
|
||||
|
||||
ip := net.ParseIP(state.IP())
|
||||
qtype := state.QType()
|
||||
for _, policy := range policies {
|
||||
// dns.TypeNone matches all query types.
|
||||
_, matchAll := policy.qtypes[dns.TypeNone]
|
||||
_, match := policy.qtypes[qtype]
|
||||
if !matchAll && !match {
|
||||
continue
|
||||
}
|
||||
|
||||
_, contained := policy.filter.GetByIP(ip)
|
||||
if !contained {
|
||||
continue
|
||||
}
|
||||
|
||||
// matched.
|
||||
return policy.action
|
||||
}
|
||||
return actionNone
|
||||
}
|
||||
|
||||
// Name implements the plugin.Handler interface.
|
||||
func (a ACL) Name() string {
|
||||
return "acl"
|
||||
}
|
|
@ -1,422 +0,0 @@
|
|||
package acl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"coredns/caddy"
|
||||
"coredns/plugin/test"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type testResponseWriter struct {
|
||||
test.ResponseWriter
|
||||
Rcode int
|
||||
}
|
||||
|
||||
func (t *testResponseWriter) setRemoteIP(ip string) {
|
||||
t.RemoteIP = ip
|
||||
}
|
||||
|
||||
// WriteMsg implement dns.ResponseWriter interface.
|
||||
func (t *testResponseWriter) WriteMsg(m *dns.Msg) error {
|
||||
t.Rcode = m.Rcode
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTestControllerWithZones(input string, zones []string) *caddy.Controller {
|
||||
ctr := caddy.NewTestController("dns", input)
|
||||
ctr.ServerBlockKeys = append(ctr.ServerBlockKeys, zones...)
|
||||
return ctr
|
||||
}
|
||||
|
||||
func TestACLServeDNS(t *testing.T) {
|
||||
type args struct {
|
||||
domain string
|
||||
sourceIP string
|
||||
qtype uint16
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
config string
|
||||
zones []string
|
||||
args args
|
||||
wantRcode int
|
||||
wantErr bool
|
||||
}{
|
||||
// IPv4 tests.
|
||||
{
|
||||
"Blacklist 1 BLOCKED",
|
||||
`acl example.org {
|
||||
block type A net 192.168.0.0/16
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"192.168.0.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 1 ALLOWED",
|
||||
`acl example.org {
|
||||
block type A net 192.168.0.0/16
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"192.167.0.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 2 BLOCKED",
|
||||
`
|
||||
acl example.org {
|
||||
block type * net 192.168.0.0/16
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"192.168.0.2",
|
||||
dns.TypeAAAA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 3 BLOCKED",
|
||||
`acl example.org {
|
||||
block type A
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"10.1.0.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 3 ALLOWED",
|
||||
`acl example.org {
|
||||
block type A
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"10.1.0.2",
|
||||
dns.TypeAAAA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 4 Single IP BLOCKED",
|
||||
`acl example.org {
|
||||
block type A net 192.168.1.2
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"192.168.1.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 4 Single IP ALLOWED",
|
||||
`acl example.org {
|
||||
block type A net 192.168.1.2
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"192.168.1.3",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Filter 1 FILTERED",
|
||||
`acl example.org {
|
||||
filter type A net 192.168.0.0/16
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"192.168.0.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Filter 1 ALLOWED",
|
||||
`acl example.org {
|
||||
filter type A net 192.168.0.0/16
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"192.167.0.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Whitelist 1 ALLOWED",
|
||||
`acl example.org {
|
||||
allow net 192.168.0.0/16
|
||||
block
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"192.168.0.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Whitelist 1 REFUSED",
|
||||
`acl example.org {
|
||||
allow type * net 192.168.0.0/16
|
||||
block
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"10.1.0.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Fine-Grained 1 REFUSED",
|
||||
`acl a.example.org {
|
||||
block type * net 192.168.1.0/24
|
||||
}`,
|
||||
[]string{"example.org"},
|
||||
args{
|
||||
"a.example.org.",
|
||||
"192.168.1.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Fine-Grained 1 ALLOWED",
|
||||
`acl a.example.org {
|
||||
block net 192.168.1.0/24
|
||||
}`,
|
||||
[]string{"example.org"},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"192.168.1.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Fine-Grained 2 REFUSED",
|
||||
`acl example.org {
|
||||
block net 192.168.1.0/24
|
||||
}`,
|
||||
[]string{"example.org"},
|
||||
args{
|
||||
"a.example.org.",
|
||||
"192.168.1.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Fine-Grained 2 ALLOWED",
|
||||
`acl {
|
||||
block net 192.168.1.0/24
|
||||
}`,
|
||||
[]string{"example.org"},
|
||||
args{
|
||||
"a.example.com.",
|
||||
"192.168.1.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Fine-Grained 3 REFUSED",
|
||||
`acl a.example.org {
|
||||
block net 192.168.1.0/24
|
||||
}
|
||||
acl b.example.org {
|
||||
block type * net 192.168.2.0/24
|
||||
}`,
|
||||
[]string{"example.org"},
|
||||
args{
|
||||
"b.example.org.",
|
||||
"192.168.2.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Fine-Grained 3 ALLOWED",
|
||||
`acl a.example.org {
|
||||
block net 192.168.1.0/24
|
||||
}
|
||||
acl b.example.org {
|
||||
block net 192.168.2.0/24
|
||||
}`,
|
||||
[]string{"example.org"},
|
||||
args{
|
||||
"b.example.org.",
|
||||
"192.168.1.2",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
// IPv6 tests.
|
||||
{
|
||||
"Blacklist 1 BLOCKED IPv6",
|
||||
`acl example.org {
|
||||
block type A net 2001:db8:abcd:0012::0/64
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"2001:db8:abcd:0012::1230",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 1 ALLOWED IPv6",
|
||||
`acl example.org {
|
||||
block type A net 2001:db8:abcd:0012::0/64
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"2001:db8:abcd:0013::0",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 2 BLOCKED IPv6",
|
||||
`acl example.org {
|
||||
block type A
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 3 Single IP BLOCKED IPv6",
|
||||
`acl example.org {
|
||||
block type A net 2001:0db8:85a3:0000:0000:8a2e:0370:7334
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 3 Single IP ALLOWED IPv6",
|
||||
`acl example.org {
|
||||
block type A net 2001:0db8:85a3:0000:0000:8a2e:0370:7334
|
||||
}`,
|
||||
[]string{},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7335",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Fine-Grained 1 REFUSED IPv6",
|
||||
`acl a.example.org {
|
||||
block type * net 2001:db8:abcd:0012::0/64
|
||||
}`,
|
||||
[]string{"example.org"},
|
||||
args{
|
||||
"a.example.org.",
|
||||
"2001:db8:abcd:0012:2019::0",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeRefused,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Fine-Grained 1 ALLOWED IPv6",
|
||||
`acl a.example.org {
|
||||
block net 2001:db8:abcd:0012::0/64
|
||||
}`,
|
||||
[]string{"example.org"},
|
||||
args{
|
||||
"www.example.org.",
|
||||
"2001:db8:abcd:0012:2019::0",
|
||||
dns.TypeA,
|
||||
},
|
||||
dns.RcodeSuccess,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctr := NewTestControllerWithZones(tt.config, tt.zones)
|
||||
a, err := parse(ctr)
|
||||
a.Next = test.NextHandler(dns.RcodeSuccess, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Error: Cannot parse acl from config: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
w := &testResponseWriter{}
|
||||
m := new(dns.Msg)
|
||||
w.setRemoteIP(tt.args.sourceIP)
|
||||
m.SetQuestion(tt.args.domain, tt.args.qtype)
|
||||
_, err = a.ServeDNS(ctx, w, m)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Error: acl.ServeDNS() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if w.Rcode != tt.wantRcode {
|
||||
t.Errorf("Error: acl.ServeDNS() Rcode = %v, want %v", w.Rcode, tt.wantRcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package acl
|
||||
|
||||
import (
|
||||
"coredns/plugin"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var (
|
||||
// RequestBlockCount is the number of DNS requests being blocked.
|
||||
RequestBlockCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: pluginName,
|
||||
Name: "blocked_requests_total",
|
||||
Help: "Counter of DNS requests being blocked.",
|
||||
}, []string{"server", "zone"})
|
||||
// RequestFilterCount is the number of DNS requests being filtered.
|
||||
RequestFilterCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: pluginName,
|
||||
Name: "filtered_requests_total",
|
||||
Help: "Counter of DNS requests being filtered.",
|
||||
}, []string{"server", "zone"})
|
||||
// RequestAllowCount is the number of DNS requests being Allowed.
|
||||
RequestAllowCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: pluginName,
|
||||
Name: "allowed_requests_total",
|
||||
Help: "Counter of DNS requests being allowed.",
|
||||
}, []string{"server"})
|
||||
)
|
|
@ -1,152 +0,0 @@
|
|||
package acl
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"coredns/caddy"
|
||||
"coredns/core/dnsserver"
|
||||
"coredns/plugin"
|
||||
|
||||
"github.com/infobloxopen/go-trees/iptree"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const pluginName = "acl"
|
||||
|
||||
func init() { plugin.Register(pluginName, setup) }
|
||||
|
||||
func newDefaultFilter() *iptree.Tree {
|
||||
defaultFilter := iptree.NewTree()
|
||||
_, IPv4All, _ := net.ParseCIDR("0.0.0.0/0")
|
||||
_, IPv6All, _ := net.ParseCIDR("::/0")
|
||||
defaultFilter.InplaceInsertNet(IPv4All, struct{}{})
|
||||
defaultFilter.InplaceInsertNet(IPv6All, struct{}{})
|
||||
return defaultFilter
|
||||
}
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
a, err := parse(c)
|
||||
if err != nil {
|
||||
return plugin.Error(pluginName, err)
|
||||
}
|
||||
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
a.Next = next
|
||||
return a
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parse(c *caddy.Controller) (ACL, error) {
|
||||
a := ACL{}
|
||||
for c.Next() {
|
||||
r := rule{}
|
||||
args := c.RemainingArgs()
|
||||
r.zones = plugin.OriginsFromArgsOrServerBlock(args, c.ServerBlockKeys)
|
||||
|
||||
for c.NextBlock() {
|
||||
p := policy{}
|
||||
|
||||
action := strings.ToLower(c.Val())
|
||||
if action == "allow" {
|
||||
p.action = actionAllow
|
||||
} else if action == "block" {
|
||||
p.action = actionBlock
|
||||
} else if action == "filter" {
|
||||
p.action = actionFilter
|
||||
} else {
|
||||
return a, c.Errf("unexpected token %q; expect 'allow', 'block', or 'filter'", c.Val())
|
||||
}
|
||||
|
||||
p.qtypes = make(map[uint16]struct{})
|
||||
p.filter = iptree.NewTree()
|
||||
|
||||
hasTypeSection := false
|
||||
hasNetSection := false
|
||||
|
||||
remainingTokens := c.RemainingArgs()
|
||||
for len(remainingTokens) > 0 {
|
||||
if !isPreservedIdentifier(remainingTokens[0]) {
|
||||
return a, c.Errf("unexpected token %q; expect 'type | net'", remainingTokens[0])
|
||||
}
|
||||
section := strings.ToLower(remainingTokens[0])
|
||||
|
||||
i := 1
|
||||
var tokens []string
|
||||
for ; i < len(remainingTokens) && !isPreservedIdentifier(remainingTokens[i]); i++ {
|
||||
tokens = append(tokens, remainingTokens[i])
|
||||
}
|
||||
remainingTokens = remainingTokens[i:]
|
||||
|
||||
if len(tokens) == 0 {
|
||||
return a, c.Errf("no token specified in %q section", section)
|
||||
}
|
||||
|
||||
switch section {
|
||||
case "type":
|
||||
hasTypeSection = true
|
||||
for _, token := range tokens {
|
||||
if token == "*" {
|
||||
p.qtypes[dns.TypeNone] = struct{}{}
|
||||
break
|
||||
}
|
||||
qtype, ok := dns.StringToType[token]
|
||||
if !ok {
|
||||
return a, c.Errf("unexpected token %q; expect legal QTYPE", token)
|
||||
}
|
||||
p.qtypes[qtype] = struct{}{}
|
||||
}
|
||||
case "net":
|
||||
hasNetSection = true
|
||||
for _, token := range tokens {
|
||||
if token == "*" {
|
||||
p.filter = newDefaultFilter()
|
||||
break
|
||||
}
|
||||
token = normalize(token)
|
||||
_, source, err := net.ParseCIDR(token)
|
||||
if err != nil {
|
||||
return a, c.Errf("illegal CIDR notation %q", token)
|
||||
}
|
||||
p.filter.InplaceInsertNet(source, struct{}{})
|
||||
}
|
||||
default:
|
||||
return a, c.Errf("unexpected token %q; expect 'type | net'", section)
|
||||
}
|
||||
}
|
||||
|
||||
// optional `type` section means all record types.
|
||||
if !hasTypeSection {
|
||||
p.qtypes[dns.TypeNone] = struct{}{}
|
||||
}
|
||||
|
||||
// optional `net` means all ip addresses.
|
||||
if !hasNetSection {
|
||||
p.filter = newDefaultFilter()
|
||||
}
|
||||
|
||||
r.policies = append(r.policies, p)
|
||||
}
|
||||
a.Rules = append(a.Rules, r)
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func isPreservedIdentifier(token string) bool {
|
||||
identifier := strings.ToLower(token)
|
||||
return identifier == "type" || identifier == "net"
|
||||
}
|
||||
|
||||
// normalize appends '/32' for any single IPv4 address and '/128' for IPv6.
|
||||
func normalize(rawNet string) string {
|
||||
if idx := strings.IndexAny(rawNet, "/"); idx >= 0 {
|
||||
return rawNet
|
||||
}
|
||||
|
||||
if idx := strings.IndexAny(rawNet, ":"); idx >= 0 {
|
||||
return rawNet + "/128"
|
||||
}
|
||||
return rawNet + "/32"
|
||||
}
|
|
@ -1,259 +0,0 @@
|
|||
package acl
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"coredns/caddy"
|
||||
)
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config string
|
||||
wantErr bool
|
||||
}{
|
||||
// IPv4 tests.
|
||||
{
|
||||
"Blacklist 1",
|
||||
`acl {
|
||||
block type A net 192.168.0.0/16
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 2",
|
||||
`acl {
|
||||
block type * net 192.168.0.0/16
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 3",
|
||||
`acl {
|
||||
block type A net *
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 4",
|
||||
`acl {
|
||||
allow type * net 192.168.1.0/24
|
||||
block type * net 192.168.0.0/16
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Filter 1",
|
||||
`acl {
|
||||
filter type A net 192.168.0.0/16
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Whitelist 1",
|
||||
`acl {
|
||||
allow type * net 192.168.0.0/16
|
||||
block type * net *
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fine-grained 1",
|
||||
`acl a.example.org {
|
||||
block type * net 192.168.1.0/24
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fine-grained 2",
|
||||
`acl a.example.org {
|
||||
block type * net 192.168.1.0/24
|
||||
}
|
||||
acl b.example.org {
|
||||
block type * net 192.168.2.0/24
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Multiple Networks 1",
|
||||
`acl example.org {
|
||||
block type * net 192.168.1.0/24 192.168.3.0/24
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Multiple Qtypes 1",
|
||||
`acl example.org {
|
||||
block type TXT ANY CNAME net 192.168.3.0/24
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Missing argument 1",
|
||||
`acl {
|
||||
block A net 192.168.0.0/16
|
||||
}`,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Missing argument 2",
|
||||
`acl {
|
||||
block type net 192.168.0.0/16
|
||||
}`,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Illegal argument 1",
|
||||
`acl {
|
||||
block type ABC net 192.168.0.0/16
|
||||
}`,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Illegal argument 2",
|
||||
`acl {
|
||||
blck type A net 192.168.0.0/16
|
||||
}`,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Illegal argument 3",
|
||||
`acl {
|
||||
block type A net 192.168.0/16
|
||||
}`,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Illegal argument 4",
|
||||
`acl {
|
||||
block type A net 192.168.0.0/33
|
||||
}`,
|
||||
true,
|
||||
},
|
||||
// IPv6 tests.
|
||||
{
|
||||
"Blacklist 1 IPv6",
|
||||
`acl {
|
||||
block type A net 2001:0db8:85a3:0000:0000:8a2e:0370:7334
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 2 IPv6",
|
||||
`acl {
|
||||
block type * net 2001:db8:85a3::8a2e:370:7334
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 3 IPv6",
|
||||
`acl {
|
||||
block type A
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Blacklist 4 IPv6",
|
||||
`acl {
|
||||
allow net 2001:db8:abcd:0012::0/64
|
||||
block net 2001:db8:abcd:0012::0/48
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Filter 1 IPv6",
|
||||
`acl {
|
||||
filter type A net 2001:0db8:85a3:0000:0000:8a2e:0370:7334
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Whitelist 1 IPv6",
|
||||
`acl {
|
||||
allow net 2001:db8:abcd:0012::0/64
|
||||
block
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fine-grained 1 IPv6",
|
||||
`acl a.example.org {
|
||||
block net 2001:db8:abcd:0012::0/64
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fine-grained 2 IPv6",
|
||||
`acl a.example.org {
|
||||
block net 2001:db8:abcd:0012::0/64
|
||||
}
|
||||
acl b.example.org {
|
||||
block net 2001:db8:abcd:0013::0/64
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Multiple Networks 1 IPv6",
|
||||
`acl example.org {
|
||||
block net 2001:db8:abcd:0012::0/64 2001:db8:85a3::8a2e:370:7334/64
|
||||
}`,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Illegal argument 1 IPv6",
|
||||
`acl {
|
||||
block type A net 2001::85a3::8a2e:370:7334
|
||||
}`,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Illegal argument 2 IPv6",
|
||||
`acl {
|
||||
block type A net 2001:db8:85a3:::8a2e:370:7334
|
||||
}`,
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctr := caddy.NewTestController("dns", tt.config)
|
||||
if err := setup(ctr); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Error: setup() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalize(t *testing.T) {
|
||||
type args struct {
|
||||
rawNet string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
"Network range 1",
|
||||
args{"10.218.10.8/24"},
|
||||
"10.218.10.8/24",
|
||||
},
|
||||
{
|
||||
"IP address 1",
|
||||
args{"10.218.10.8"},
|
||||
"10.218.10.8/32",
|
||||
},
|
||||
{
|
||||
"IPv6 address 1",
|
||||
args{"2001:0db8:85a3:0000:0000:8a2e:0370:7334"},
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7334/128",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := normalize(tt.args.rawNet); got != tt.want {
|
||||
t.Errorf("Error: normalize() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/file"
|
||||
"coredns/plugin/metrics"
|
||||
|
||||
"coredns/plugin/pkg/upstream"
|
||||
"coredns/plugin/transfer"
|
||||
"coredns/request"
|
||||
|
@ -22,7 +22,6 @@ type (
|
|||
Next plugin.Handler
|
||||
*Zones
|
||||
|
||||
metrics *metrics.Metrics
|
||||
transfer *transfer.Transfer
|
||||
loader
|
||||
}
|
||||
|
@ -82,7 +81,14 @@ func (a Auto) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
|||
case file.Delegation:
|
||||
m.Authoritative = false
|
||||
case file.ServerFailure:
|
||||
return dns.RcodeServerFailure, nil
|
||||
// If the result is SERVFAIL and the answer is non-empty, then the SERVFAIL came from an
|
||||
// external CNAME lookup and the answer contains the CNAME with no target record. We should
|
||||
// write the CNAME record to the client instead of sending an empty SERVFAIL response.
|
||||
if len(m.Answer) == 0 {
|
||||
return dns.RcodeServerFailure, nil
|
||||
}
|
||||
// The rcode in the response should be the rcode received from the target lookup. RFC 6604 section 3
|
||||
m.Rcode = dns.RcodeServerFailure
|
||||
}
|
||||
|
||||
w.WriteMsg(m)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package auto
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
@ -9,7 +10,6 @@ import (
|
|||
"coredns/caddy"
|
||||
"coredns/core/dnsserver"
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/metrics"
|
||||
clog "coredns/plugin/pkg/log"
|
||||
"coredns/plugin/pkg/upstream"
|
||||
"coredns/plugin/transfer"
|
||||
|
@ -26,10 +26,6 @@ func setup(c *caddy.Controller) error {
|
|||
}
|
||||
|
||||
c.OnStartup(func() error {
|
||||
m := dnsserver.GetConfig(c).Handler("prometheus")
|
||||
if m != nil {
|
||||
(&a).metrics = m.(*metrics.Metrics)
|
||||
}
|
||||
t := dnsserver.GetConfig(c).Handler("transfer")
|
||||
if t != nil {
|
||||
(&a).transfer = t.(*transfer.Transfer)
|
||||
|
@ -44,7 +40,9 @@ func setup(c *caddy.Controller) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if a.loader.ReloadInterval == 0 {
|
||||
return nil
|
||||
}
|
||||
go func() {
|
||||
ticker := time.NewTicker(a.loader.ReloadInterval)
|
||||
for {
|
||||
|
@ -131,7 +129,14 @@ func autoParse(c *caddy.Controller) (Auto, error) {
|
|||
}
|
||||
|
||||
case "reload":
|
||||
d, err := time.ParseDuration(c.RemainingArgs()[0])
|
||||
t := c.RemainingArgs()
|
||||
if len(t) < 1 {
|
||||
return a, errors.New("reload duration value is expected")
|
||||
}
|
||||
d, err := time.ParseDuration(t[0])
|
||||
if d < 0 {
|
||||
err = errors.New("invalid duration")
|
||||
}
|
||||
if err != nil {
|
||||
return a, plugin.Error("file", err)
|
||||
}
|
||||
|
|
|
@ -126,3 +126,52 @@ func TestAutoParse(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupReload(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "reload valid",
|
||||
config: `auto {
|
||||
directory .
|
||||
reload 5s
|
||||
}`,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "reload disable",
|
||||
config: `auto {
|
||||
directory .
|
||||
reload 0
|
||||
}`,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "reload invalid",
|
||||
config: `auto {
|
||||
directory .
|
||||
reload -1s
|
||||
}`,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "reload invalid",
|
||||
config: `auto {
|
||||
directory .
|
||||
reload
|
||||
}`,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctr := caddy.NewTestController("dns", tt.config)
|
||||
if err := setup(ctr); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Error: setup() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,9 +56,6 @@ func (a Auto) Walk() error {
|
|||
|
||||
a.Zones.Add(zo, origin, a.transfer)
|
||||
|
||||
if a.metrics != nil {
|
||||
a.metrics.AddZone(origin)
|
||||
}
|
||||
|
||||
a.transfer.Notify(origin)
|
||||
|
||||
|
@ -74,9 +71,6 @@ func (a Auto) Walk() error {
|
|||
continue
|
||||
}
|
||||
|
||||
if a.metrics != nil {
|
||||
a.metrics.RemoveZone(origin)
|
||||
}
|
||||
|
||||
a.Zones.Remove(origin)
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package auto
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
@ -67,13 +66,13 @@ func TestWalkNonExistent(t *testing.T) {
|
|||
}
|
||||
|
||||
func createFiles() (string, error) {
|
||||
dir, err := ioutil.TempDir(os.TempDir(), "coredns")
|
||||
dir, err := os.MkdirTemp(os.TempDir(), "coredns")
|
||||
if err != nil {
|
||||
return dir, err
|
||||
}
|
||||
|
||||
for _, name := range dbFiles {
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, name), []byte(zoneContent), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(dir, name), []byte(zoneContent), 0644); err != nil {
|
||||
return dir, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ func (z *Zones) Zones(name string) *file.Zone {
|
|||
return zo
|
||||
}
|
||||
|
||||
// Add adds a new zone into z. If zo.NoReload is false, the
|
||||
// Add adds a new zone into z. If z.ReloadInterval is not zero, the
|
||||
// reload goroutine is started.
|
||||
func (z *Zones) Add(zo *file.Zone, name string, t *transfer.Transfer) {
|
||||
z.Lock()
|
||||
|
|
|
@ -14,7 +14,7 @@ client - with some CNAME hackery to let the client accept the reply.
|
|||
|
||||
If all queries return NXDOMAIN we return the original as-is and let the client
|
||||
continue searching. The client will go to the next element in the search path,
|
||||
but we won’t do any more autopathing. It means that in the failure case, you do
|
||||
but we won?t do any more autopathing. It means that in the failure case, you do
|
||||
more work, since the server looks it up, then the client still needs to go
|
||||
through the search path.
|
||||
|
||||
|
@ -35,7 +35,6 @@ import (
|
|||
"context"
|
||||
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/metrics"
|
||||
"coredns/plugin/pkg/dnsutil"
|
||||
"coredns/plugin/pkg/nonwriter"
|
||||
"coredns/request"
|
||||
|
@ -133,7 +132,6 @@ func (a *AutoPath) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
|
|||
|
||||
// Write whatever non-nxdomain answer we've found.
|
||||
w.WriteMsg(msg)
|
||||
autoPathCount.WithLabelValues(metrics.WithServer(ctx)).Add(1)
|
||||
return rcode, err
|
||||
|
||||
}
|
||||
|
|
|
@ -101,3 +101,6 @@ bad.example.com {
|
|||
forward . 5.6.7.8
|
||||
}
|
||||
```
|
||||
|
||||
Also on MacOS there is an (open) bug where this doesn't work properly. See
|
||||
<https://github.com/miekg/dns/issues/724> for details, but no solution.
|
||||
|
|
|
@ -75,7 +75,8 @@ If monitoring is enabled (via the *prometheus* plugin) then the following metric
|
|||
|
||||
* `coredns_cache_entries{server, type}` - Total elements in the cache by cache type.
|
||||
* `coredns_cache_hits_total{server, type}` - Counter of cache hits by cache type.
|
||||
* `coredns_cache_misses_total{server}` - Counter of cache misses.
|
||||
* `coredns_cache_misses_total{server}` - Counter of cache misses. - Deprecated, derive misses from cache hits/requests counters.
|
||||
* `coredns_cache_requests_total{server}` - Counter of cache requests.
|
||||
* `coredns_cache_prefetch_total{server}` - Counter of times the cache has prefetched a cached item.
|
||||
* `coredns_cache_drops_total{server}` - Counter of responses excluded from the cache due to request/response question name mismatch.
|
||||
* `coredns_cache_served_stale_total{server}` - Counter of requests served from stale cache entries.
|
||||
|
|
|
@ -181,6 +181,10 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
|||
res.Ns = filterRRSlice(res.Ns, ttl, w.do, false)
|
||||
res.Extra = filterRRSlice(res.Extra, ttl, w.do, false)
|
||||
|
||||
if !w.do {
|
||||
res.AuthenticatedData = false // unset AD bit if client is not OK with DNSSEC
|
||||
}
|
||||
|
||||
return w.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ func isDNSSEC(r dns.RR) bool {
|
|||
// returned.
|
||||
func filterRRSlice(rrs []dns.RR, ttl uint32, do, dup bool) []dns.RR {
|
||||
j := 0
|
||||
rs := make([]dns.RR, len(rrs), len(rrs))
|
||||
rs := make([]dns.RR, len(rrs))
|
||||
for _, r := range rrs {
|
||||
if !do && isDNSSEC(r) {
|
||||
continue
|
||||
|
|
|
@ -23,7 +23,8 @@ func TestResponseWithDNSSEC(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Qname: "invent.example.org.", Qtype: dns.TypeA,
|
||||
Do: true,
|
||||
Do: true,
|
||||
AuthenticatedData: true,
|
||||
Answer: []dns.RR{
|
||||
test.CNAME("invent.example.org. 1781 IN CNAME leptone.example.org."),
|
||||
test.RRSIG("invent.example.org. 1781 IN RRSIG CNAME 8 3 1800 20201012085750 20200912082613 57411 example.org. ijSv5FmsNjFviBcOFwQgqjt073lttxTTNqkno6oMa3DD3kC+"),
|
||||
|
@ -40,6 +41,9 @@ func TestResponseWithDNSSEC(t *testing.T) {
|
|||
m := tc.Msg()
|
||||
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||
c.ServeDNS(context.TODO(), rec, m)
|
||||
if tc.AuthenticatedData != rec.Msg.AuthenticatedData {
|
||||
t.Errorf("Test %d, expected AuthenticatedData=%v", i, tc.AuthenticatedData)
|
||||
}
|
||||
if err := test.Section(tc, test.Answer, rec.Msg.Answer); err != nil {
|
||||
t.Errorf("Test %d, expected no error, got %s", i, err)
|
||||
}
|
||||
|
@ -64,6 +68,7 @@ func dnssecHandler() plugin.Handler {
|
|||
m := new(dns.Msg)
|
||||
m.SetQuestion("example.org.", dns.TypeA)
|
||||
|
||||
m.AuthenticatedData = true
|
||||
m.Answer = make([]dns.RR, 4)
|
||||
m.Answer[0] = test.CNAME("invent.example.org. 1781 IN CNAME leptone.example.org.")
|
||||
m.Answer[1] = test.RRSIG("invent.example.org. 1781 IN RRSIG CNAME 8 3 1800 20201012085750 20200912082613 57411 example.org. ijSv5FmsNjFviBcOFwQgqjt073lttxTTNqkno6oMa3DD3kC+")
|
||||
|
|
|
@ -6,12 +6,30 @@ import (
|
|||
"time"
|
||||
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/metrics"
|
||||
"coredns/request"
|
||||
"coredns/core/dnsserver"
|
||||
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// WithServer returns the current server handling the request. It returns the
|
||||
// server listening address: <scheme>://[<bind>]:<port> Normally this is
|
||||
// something like "dns://:53", but if the bind plugin is used, i.e. "bind
|
||||
// 127.0.0.53", it will be "dns://127.0.0.53:53", etc. If not address is found
|
||||
// the empty string is returned.
|
||||
//
|
||||
// Basic usage with a metric:
|
||||
//
|
||||
// <metric>.WithLabelValues(metrics.WithServer(ctx), labels..).Add(1)
|
||||
func WithServer(ctx context.Context) string {
|
||||
srv := ctx.Value(dnsserver.Key{})
|
||||
if srv == nil {
|
||||
return ""
|
||||
}
|
||||
return srv.(*dnsserver.Server).Addr
|
||||
}
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
rc := r.Copy() // We potentially modify r, to prevent other plugins from seeing this (r is a pointer), copy r into rc.
|
||||
|
@ -24,7 +42,7 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
}
|
||||
|
||||
now := c.now().UTC()
|
||||
server := metrics.WithServer(ctx)
|
||||
server := WithServer(ctx)
|
||||
|
||||
// On cache miss, if the request has the OPT record and the DO bit set we leave the message as-is. If there isn't a DO bit
|
||||
// set we will modify the request to _add_ one. This means we will always do DNSSEC lookups on cache misses.
|
||||
|
@ -91,6 +109,7 @@ func (c *Cache) Name() string { return "cache" }
|
|||
|
||||
func (c *Cache) get(now time.Time, state request.Request, server string) (*item, bool) {
|
||||
k := hash(state.Name(), state.QType())
|
||||
cacheRequests.WithLabelValues(server).Inc()
|
||||
|
||||
if i, ok := c.ncache.Get(k); ok && i.(*item).ttl(now) > 0 {
|
||||
cacheHits.WithLabelValues(server, Denial).Inc()
|
||||
|
@ -108,6 +127,7 @@ func (c *Cache) get(now time.Time, state request.Request, server string) (*item,
|
|||
// getIgnoreTTL unconditionally returns an item if it exists in the cache.
|
||||
func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string) *item {
|
||||
k := hash(state.Name(), state.QType())
|
||||
cacheRequests.WithLabelValues(server).Inc()
|
||||
|
||||
if i, ok := c.ncache.Get(k); ok {
|
||||
ttl := i.(*item).ttl(now)
|
||||
|
|
|
@ -15,6 +15,13 @@ var (
|
|||
Name: "entries",
|
||||
Help: "The number of elements in the cache.",
|
||||
}, []string{"server", "type"})
|
||||
// cacheRequests is a counter of all requests through the cache.
|
||||
cacheRequests = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "requests_total",
|
||||
Help: "The count of cache requests.",
|
||||
}, []string{"server"})
|
||||
// cacheHits is counter of cache hits by cache type.
|
||||
cacheHits = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
|
@ -22,12 +29,12 @@ var (
|
|||
Name: "hits_total",
|
||||
Help: "The count of cache hits.",
|
||||
}, []string{"server", "type"})
|
||||
// cacheMisses is the counter of cache misses.
|
||||
// cacheMisses is the counter of cache misses. - Deprecated
|
||||
cacheMisses = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "misses_total",
|
||||
Help: "The count of cache misses.",
|
||||
Help: "The count of cache misses. Deprecated, derive misses from cache hits/requests counters.",
|
||||
}, []string{"server"})
|
||||
// cachePrefetches is the number of time the cache has prefetched a cached item.
|
||||
cachePrefetches = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package chaos
|
||||
|
||||
// Owners are all GitHub handlers of all maintainers.
|
||||
var Owners = []string{"bradbeam", "chrisohaver", "darshanime", "dilyevsky", "ekleiner", "fastest963", "greenpau", "ihac", "inigohu", "isolus", "johnbelamaric", "miekg", "nchrisdk", "nitisht", "pmoroney", "rajansandeep", "rdrozhdzh", "rtreffer", "stp-ip", "superq", "varyoo", "ykhr53", "yongtang", "zouyee"}
|
||||
var Owners = []string{"bradbeam", "chrisohaver", "darshanime", "dilyevsky", "ekleiner", "fastest963", "greenpau", "ihac", "inigohu", "isolus", "johnbelamaric", "miekg", "mqasimsarfraz", "nchrisdk", "nitisht", "pmoroney", "rajansandeep", "rdrozhdzh", "rtreffer", "snebel29", "stp-ip", "superq", "varyoo", "ykhr53", "yongtang", "zouyee"}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"time"
|
||||
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/metrics"
|
||||
"coredns/plugin/pkg/nonwriter"
|
||||
"coredns/plugin/pkg/response"
|
||||
"coredns/request"
|
||||
|
@ -59,7 +58,6 @@ func (d *DNS64) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
return dns.RcodeServerFailure, err
|
||||
}
|
||||
|
||||
RequestsTranslatedCount.WithLabelValues(metrics.WithServer(ctx)).Inc()
|
||||
w.WriteMsg(msg)
|
||||
return msg.MsgHdr.Rcode, nil
|
||||
}
|
||||
|
|
|
@ -3,17 +3,36 @@ package dnssec
|
|||
import (
|
||||
"context"
|
||||
|
||||
"coredns/core/dnsserver"
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/metrics"
|
||||
"coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// WithServer returns the current server handling the request. It returns the
|
||||
// server listening address: <scheme>://[<bind>]:<port> Normally this is
|
||||
// something like "dns://:53", but if the bind plugin is used, i.e. "bind
|
||||
// 127.0.0.53", it will be "dns://127.0.0.53:53", etc. If not address is found
|
||||
// the empty string is returned.
|
||||
//
|
||||
// Basic usage with a metric:
|
||||
//
|
||||
// <metric>.WithLabelValues(metrics.WithServer(ctx), labels..).Add(1)
|
||||
func WithServer(ctx context.Context) string {
|
||||
srv := ctx.Value(dnsserver.Key{})
|
||||
if srv == nil {
|
||||
return ""
|
||||
}
|
||||
return srv.(*dnsserver.Server).Addr
|
||||
}
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (d Dnssec) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
state := request.Request{W: w, Req: r}
|
||||
|
||||
server := WithServer(ctx)
|
||||
|
||||
do := state.Do()
|
||||
qname := state.Name()
|
||||
qtype := state.QType()
|
||||
|
@ -23,7 +42,6 @@ func (d Dnssec) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
}
|
||||
|
||||
state.Zone = zone
|
||||
server := metrics.WithServer(ctx)
|
||||
|
||||
// Intercept queries for DNSKEY, but only if one of the zones matches the qname, otherwise we let
|
||||
// the query through.
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package dnssec
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -10,19 +9,19 @@ import (
|
|||
)
|
||||
|
||||
func TestSetupDnssec(t *testing.T) {
|
||||
if err := ioutil.WriteFile("Kcluster.local.key", []byte(keypub), 0644); err != nil {
|
||||
if err := os.WriteFile("Kcluster.local.key", []byte(keypub), 0644); err != nil {
|
||||
t.Fatalf("Failed to write pub key file: %s", err)
|
||||
}
|
||||
defer func() { os.Remove("Kcluster.local.key") }()
|
||||
if err := ioutil.WriteFile("Kcluster.local.private", []byte(keypriv), 0644); err != nil {
|
||||
if err := os.WriteFile("Kcluster.local.private", []byte(keypriv), 0644); err != nil {
|
||||
t.Fatalf("Failed to write private key file: %s", err)
|
||||
}
|
||||
defer func() { os.Remove("Kcluster.local.private") }()
|
||||
if err := ioutil.WriteFile("ksk_Kcluster.local.key", []byte(kskpub), 0644); err != nil {
|
||||
if err := os.WriteFile("ksk_Kcluster.local.key", []byte(kskpub), 0644); err != nil {
|
||||
t.Fatalf("Failed to write pub key file: %s", err)
|
||||
}
|
||||
defer func() { os.Remove("ksk_Kcluster.local.key") }()
|
||||
if err := ioutil.WriteFile("ksk_Kcluster.local.private", []byte(kskpriv), 0644); err != nil {
|
||||
if err := os.WriteFile("ksk_Kcluster.local.private", []byte(kskpriv), 0644); err != nil {
|
||||
t.Fatalf("Failed to write private key file: %s", err)
|
||||
}
|
||||
defer func() { os.Remove("ksk_Kcluster.local.private") }()
|
||||
|
|
|
@ -22,12 +22,12 @@ Extra knobs are available with an expanded syntax:
|
|||
|
||||
~~~
|
||||
errors {
|
||||
consolidate DURATION REGEXP
|
||||
consolidate DURATION REGEXP [LEVEL]
|
||||
}
|
||||
~~~
|
||||
|
||||
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.
|
||||
|
||||
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 with
|
||||
log level, which is configurable by optional option **LEVEL**. Supported options for **LEVEL** option are `warning`,`error`,`info` and `debug`.
|
||||
~~~
|
||||
2 errors like '^read udp .* i/o timeout$' occurred in last 30s
|
||||
~~~
|
||||
|
@ -47,13 +47,15 @@ example.org {
|
|||
}
|
||||
~~~
|
||||
|
||||
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 ".
|
||||
Use the *forward* plugin to resolve queries via 8.8.8.8 and print consolidated messages
|
||||
for errors with suffix " i/o timeout" as warnings,
|
||||
and errors with prefix "Failed to " as errors.
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
forward . 8.8.8.8
|
||||
errors {
|
||||
consolidate 5m ".* i/o timeout$"
|
||||
consolidate 5m ".* i/o timeout$" warning
|
||||
consolidate 30s "^Failed to .+"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,11 @@ import (
|
|||
var log = clog.NewWithPlugin("errors")
|
||||
|
||||
type pattern struct {
|
||||
ptimer unsafe.Pointer
|
||||
count uint32
|
||||
period time.Duration
|
||||
pattern *regexp.Regexp
|
||||
ptimer unsafe.Pointer
|
||||
count uint32
|
||||
period time.Duration
|
||||
pattern *regexp.Regexp
|
||||
logCallback func(format string, v ...interface{})
|
||||
}
|
||||
|
||||
func (p *pattern) timer() *time.Timer {
|
||||
|
@ -46,7 +47,7 @@ func newErrorHandler() *errorHandler {
|
|||
func (h *errorHandler) logPattern(i int) {
|
||||
cnt := atomic.SwapUint32(&h.patterns[i].count, 0)
|
||||
if cnt > 0 {
|
||||
log.Errorf("%d errors like '%s' occurred in last %s",
|
||||
h.patterns[i].logCallback("%d errors like '%s' occurred in last %s",
|
||||
cnt, h.patterns[i].pattern.String(), h.patterns[i].period)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/pkg/dnstest"
|
||||
clog "coredns/plugin/pkg/log"
|
||||
"coredns/plugin/test"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
@ -71,21 +72,56 @@ func TestErrors(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLogPattern(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
golog.SetOutput(&buf)
|
||||
|
||||
h := &errorHandler{
|
||||
patterns: []*pattern{{
|
||||
count: 4,
|
||||
period: 2 * time.Second,
|
||||
pattern: regexp.MustCompile("^error.*!$"),
|
||||
}},
|
||||
type args struct {
|
||||
logCallback func(format string, v ...interface{})
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "error log",
|
||||
args: args{logCallback: log.Errorf},
|
||||
want: "[ERROR] plugin/errors: 4 errors like '^error.*!$' occurred in last 2s",
|
||||
},
|
||||
{
|
||||
name: "warn log",
|
||||
args: args{logCallback: log.Warningf},
|
||||
want: "[WARNING] plugin/errors: 4 errors like '^error.*!$' occurred in last 2s",
|
||||
},
|
||||
{
|
||||
name: "info log",
|
||||
args: args{logCallback: log.Infof},
|
||||
want: "[INFO] plugin/errors: 4 errors like '^error.*!$' occurred in last 2s",
|
||||
},
|
||||
{
|
||||
name: "debug log",
|
||||
args: args{logCallback: log.Debugf},
|
||||
want: "[DEBUG] plugin/errors: 4 errors like '^error.*!$' occurred in last 2s",
|
||||
},
|
||||
}
|
||||
h.logPattern(0)
|
||||
|
||||
expLog := "4 errors like '^error.*!$' occurred in last 2s"
|
||||
if log := buf.String(); !strings.Contains(log, expLog) {
|
||||
t.Errorf("Expected log %q, but got %q", expLog, log)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
clog.D.Set()
|
||||
golog.SetOutput(&buf)
|
||||
|
||||
h := &errorHandler{
|
||||
patterns: []*pattern{{
|
||||
count: 4,
|
||||
period: 2 * time.Second,
|
||||
pattern: regexp.MustCompile("^error.*!$"),
|
||||
logCallback: tt.args.logCallback,
|
||||
}},
|
||||
}
|
||||
h.logPattern(0)
|
||||
|
||||
if log := buf.String(); !strings.Contains(log, tt.want) {
|
||||
t.Errorf("Expected log %q, but got %q", tt.want, log)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,8 +188,9 @@ func TestStop(t *testing.T) {
|
|||
|
||||
h := &errorHandler{
|
||||
patterns: []*pattern{{
|
||||
period: 2 * time.Second,
|
||||
pattern: regexp.MustCompile("^error.*!$"),
|
||||
period: 2 * time.Second,
|
||||
pattern: regexp.MustCompile("^error.*!$"),
|
||||
logCallback: log.Errorf,
|
||||
}},
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ func parseBlock(c *caddy.Controller, h *errorHandler) error {
|
|||
}
|
||||
|
||||
args := c.RemainingArgs()
|
||||
if len(args) != 2 {
|
||||
if len(args) < 2 || len(args) > 3 {
|
||||
return c.ArgErr()
|
||||
}
|
||||
p, err := time.ParseDuration(args[0])
|
||||
|
@ -77,7 +77,30 @@ func parseBlock(c *caddy.Controller, h *errorHandler) error {
|
|||
if err != nil {
|
||||
return c.Err(err.Error())
|
||||
}
|
||||
h.patterns = append(h.patterns, &pattern{period: p, pattern: re})
|
||||
lc, err := parseLogLevel(c, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.patterns = append(h.patterns, &pattern{period: p, pattern: re, logCallback: lc})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseLogLevel(c *caddy.Controller, args []string) (func(format string, v ...interface{}), error) {
|
||||
if len(args) != 3 {
|
||||
return log.Errorf, nil
|
||||
}
|
||||
|
||||
switch args[2] {
|
||||
case "warning":
|
||||
return log.Warningf, nil
|
||||
case "error":
|
||||
return log.Errorf, nil
|
||||
case "info":
|
||||
return log.Infof, nil
|
||||
case "debug":
|
||||
return log.Debugf, nil
|
||||
default:
|
||||
return nil, c.Errf("unknown log level argument in consolidate: %s", args[2])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package errors
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
golog "log"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"coredns/caddy"
|
||||
clog "coredns/plugin/pkg/log"
|
||||
)
|
||||
|
||||
func TestErrorsParse(t *testing.T) {
|
||||
|
@ -67,3 +71,65 @@ func TestErrorsParse(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProperLogCallbackIsSet(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
inputErrorsRules string
|
||||
wantLogLevel string
|
||||
}{
|
||||
{
|
||||
name: "warning is parsed properly",
|
||||
inputErrorsRules: `errors {
|
||||
consolidate 1m .* warning
|
||||
}`,
|
||||
wantLogLevel: "[WARNING]",
|
||||
},
|
||||
{
|
||||
name: "error is parsed properly",
|
||||
inputErrorsRules: `errors {
|
||||
consolidate 1m .* error
|
||||
}`,
|
||||
wantLogLevel: "[ERROR]",
|
||||
},
|
||||
{
|
||||
name: "info is parsed properly",
|
||||
inputErrorsRules: `errors {
|
||||
consolidate 1m .* info
|
||||
}`,
|
||||
wantLogLevel: "[INFO]",
|
||||
},
|
||||
{
|
||||
name: "debug is parsed properly",
|
||||
inputErrorsRules: `errors {
|
||||
consolidate 1m .* debug
|
||||
}`,
|
||||
wantLogLevel: "[DEBUG]",
|
||||
},
|
||||
{
|
||||
name: "default is error",
|
||||
inputErrorsRules: `errors {
|
||||
consolidate 1m .*
|
||||
}`,
|
||||
wantLogLevel: "[ERROR]",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
golog.SetOutput(&buf)
|
||||
clog.D.Set()
|
||||
|
||||
c := caddy.NewTestController("dns", tt.inputErrorsRules)
|
||||
h, _ := errorsParse(c)
|
||||
|
||||
l := h.patterns[0].logCallback
|
||||
l("some error happened")
|
||||
|
||||
if log := buf.String(); !strings.Contains(log, tt.wantLogLevel) {
|
||||
t.Errorf("Expected log %q, but got %q", tt.wantLogLevel, log)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,14 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
|||
case Delegation:
|
||||
m.Authoritative = false
|
||||
case ServerFailure:
|
||||
return dns.RcodeServerFailure, nil
|
||||
// If the result is SERVFAIL and the answer is non-empty, then the SERVFAIL came from an
|
||||
// external CNAME lookup and the answer contains the CNAME with no target record. We should
|
||||
// write the CNAME record to the client instead of sending an empty SERVFAIL response.
|
||||
if len(m.Answer) == 0 {
|
||||
return dns.RcodeServerFailure, nil
|
||||
}
|
||||
// The rcode in the response should be the rcode received from the target lookup. RFC 6604 section 3
|
||||
m.Rcode = dns.RcodeServerFailure
|
||||
}
|
||||
|
||||
w.WriteMsg(m)
|
||||
|
|
|
@ -56,10 +56,10 @@ func (z *Zone) Lookup(ctx context.Context, state request.Request, qname string)
|
|||
}
|
||||
|
||||
var (
|
||||
found, shot bool
|
||||
parts string
|
||||
i, maxLabelNum int
|
||||
elem, wildElem, nextElem *tree.Elem
|
||||
found, shot bool
|
||||
parts string
|
||||
i int
|
||||
elem, wildElem *tree.Elem
|
||||
)
|
||||
|
||||
loop, _ := ctx.Value(dnsserver.LoopKey{}).(int)
|
||||
|
@ -92,12 +92,6 @@ func (z *Zone) Lookup(ctx context.Context, state request.Request, qname string)
|
|||
break
|
||||
}
|
||||
|
||||
if nextElem, found = tr.Next(parts); found {
|
||||
if dns.IsSubDomain(parts, nextElem.Name()) {
|
||||
maxLabelNum = z.origLen + i
|
||||
}
|
||||
}
|
||||
|
||||
elem, found = tr.Search(parts)
|
||||
if !found {
|
||||
// Apex will always be found, when we are here we can search for a wildcard
|
||||
|
@ -121,8 +115,21 @@ func (z *Zone) Lookup(ctx context.Context, state request.Request, qname string)
|
|||
// Only one DNAME is allowed per name. We just pick the first one to synthesize from.
|
||||
dname := dnamerrs[0]
|
||||
if cname := synthesizeCNAME(state.Name(), dname.(*dns.DNAME)); cname != nil {
|
||||
ctx = context.WithValue(ctx, dnsserver.LoopKey{}, loop+1)
|
||||
answer, ns, extra, rcode := z.externalLookup(ctx, state, elem, []dns.RR{cname})
|
||||
var (
|
||||
answer, ns, extra []dns.RR
|
||||
rcode Result
|
||||
)
|
||||
|
||||
// We don't need to chase CNAME chain for synthesized CNAME
|
||||
if qtype == dns.TypeCNAME {
|
||||
answer = []dns.RR{cname}
|
||||
ns = ap.ns(do)
|
||||
extra = nil
|
||||
rcode = Success
|
||||
} else {
|
||||
ctx = context.WithValue(ctx, dnsserver.LoopKey{}, loop+1)
|
||||
answer, ns, extra, rcode = z.externalLookup(ctx, state, elem, []dns.RR{cname})
|
||||
}
|
||||
|
||||
if do {
|
||||
sigs := elem.Type(dns.TypeRRSIG)
|
||||
|
@ -207,19 +214,9 @@ func (z *Zone) Lookup(ctx context.Context, state request.Request, qname string)
|
|||
|
||||
// Found wildcard.
|
||||
if wildElem != nil {
|
||||
// if the domain's longest matching parent domain is subdomain of the wildcard,
|
||||
// in other words, the domain‘s max number of labels matched is >= number of labels of the wildcard
|
||||
if maxLabelNum >= dns.CountLabel(wildElem.Name()) {
|
||||
ret := ap.soa(do)
|
||||
if do {
|
||||
nsec := typeFromElem(wildElem, dns.TypeNSEC, do)
|
||||
ret = append(ret, nsec...)
|
||||
}
|
||||
return nil, ret, nil, NameError
|
||||
}
|
||||
|
||||
auth := ap.ns(do)
|
||||
if rrs := wildElem.TypeForWildcard(dns.TypeCNAME, qname); len(rrs) > 0 {
|
||||
|
||||
if rrs := wildElem.TypeForWildcard(dns.TypeCNAME, qname); len(rrs) > 0 && qtype != dns.TypeCNAME {
|
||||
ctx = context.WithValue(ctx, dnsserver.LoopKey{}, loop+1)
|
||||
return z.externalLookup(ctx, state, wildElem, rrs)
|
||||
}
|
||||
|
@ -386,7 +383,7 @@ Redo:
|
|||
func (z *Zone) doLookup(ctx context.Context, state request.Request, target string, qtype uint16) ([]dns.RR, Result) {
|
||||
m, e := z.Upstream.Lookup(ctx, state, target, qtype)
|
||||
if e != nil {
|
||||
return nil, Success
|
||||
return nil, ServerFailure
|
||||
}
|
||||
if m == nil {
|
||||
return nil, Success
|
||||
|
|
|
@ -96,10 +96,34 @@ var dnsTestCases = []test.Case{
|
|||
Ns: miekAuth,
|
||||
},
|
||||
{
|
||||
Qname: "ent.miek.nl.", Qtype: dns.TypeA,
|
||||
Ns: []dns.RR{
|
||||
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
||||
Qname: "asterisk.x.miek.nl.", Qtype: dns.TypeCNAME,
|
||||
Answer: []dns.RR{
|
||||
test.CNAME("asterisk.x.miek.nl. 1800 IN CNAME www.miek.nl."),
|
||||
},
|
||||
Ns: miekAuth,
|
||||
},
|
||||
{
|
||||
Qname: "asterisk.y.miek.nl.", Qtype: dns.TypeA,
|
||||
Answer: []dns.RR{
|
||||
test.A("asterisk.y.miek.nl. 1800 IN A 139.162.196.78"),
|
||||
},
|
||||
Ns: miekAuth,
|
||||
},
|
||||
{
|
||||
Qname: "foo.dname.miek.nl.", Qtype: dns.TypeCNAME,
|
||||
Answer: []dns.RR{
|
||||
test.DNAME("dname.miek.nl. 1800 IN DNAME x.miek.nl."),
|
||||
test.CNAME("foo.dname.miek.nl. 1800 IN CNAME foo.x.miek.nl."),
|
||||
},
|
||||
Ns: miekAuth,
|
||||
},
|
||||
{
|
||||
Qname: "ext-cname.miek.nl.", Qtype: dns.TypeA,
|
||||
Answer: []dns.RR{
|
||||
test.CNAME("ext-cname.miek.nl. 1800 IN CNAME example.com."),
|
||||
},
|
||||
Rcode: dns.RcodeServerFailure,
|
||||
Ns: miekAuth,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -197,8 +221,11 @@ a IN A 139.162.196.78
|
|||
IN AAAA 2a01:7e00::f03c:91ff:fef1:6735
|
||||
www IN CNAME a
|
||||
archive IN CNAME a
|
||||
*.x IN CNAME www
|
||||
*.y IN A 139.162.196.78
|
||||
dname IN DNAME x
|
||||
|
||||
srv IN SRV 10 10 8080 a.miek.nl.
|
||||
mx IN MX 10 a.miek.nl.
|
||||
|
||||
test.ent IN A 139.162.196.79`
|
||||
ext-cname IN CNAME example.com.`
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"coredns/plugin/transfer"
|
||||
)
|
||||
|
||||
// Reload reloads a zone when it is changed on disk. If z.NoReload is true, no reloading will be done.
|
||||
// Reload reloads a zone when it is changed on disk. If z.ReloadInterval is zero, no reloading will be done.
|
||||
func (z *Zone) Reload(t *transfer.Transfer) error {
|
||||
if z.ReloadInterval == 0 {
|
||||
return nil
|
||||
|
|
|
@ -2,7 +2,6 @@ package file
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -56,7 +55,7 @@ func TestZoneReload(t *testing.T) {
|
|||
if len(rrs) != 5 {
|
||||
t.Fatalf("Expected 5 RRs, got %d", len(rrs))
|
||||
}
|
||||
if err := ioutil.WriteFile(fileName, []byte(reloadZone2Test), 0644); err != nil {
|
||||
if err := os.WriteFile(fileName, []byte(reloadZone2Test), 0644); err != nil {
|
||||
t.Fatalf("Failed to write new zone data: %s", err)
|
||||
}
|
||||
// Could still be racy, but we need to wait a bit for the event to be seen
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
@ -108,7 +109,11 @@ func fileParse(c *caddy.Controller) (Zones, error) {
|
|||
for c.NextBlock() {
|
||||
switch c.Val() {
|
||||
case "reload":
|
||||
d, err := time.ParseDuration(c.RemainingArgs()[0])
|
||||
t := c.RemainingArgs()
|
||||
if len(t) < 1 {
|
||||
return Zones{}, errors.New("reload duration value is expected")
|
||||
}
|
||||
d, err := time.ParseDuration(t[0])
|
||||
if err != nil {
|
||||
return Zones{}, plugin.Error("file", err)
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ func (n *Node) print() {
|
|||
}
|
||||
if nodesInCurrentLevel == 0 {
|
||||
fmt.Println()
|
||||
nodesInCurrentLevel = nodesInNextLevel
|
||||
nodesInNextLevel = 0
|
||||
}
|
||||
nodesInCurrentLevel = nodesInNextLevel
|
||||
nodesInNextLevel = 0
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
package tree
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func TestPrint(t *testing.T) {
|
||||
rr1 := dns.A{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: dns.Fqdn("server1.example.com"),
|
||||
Rrtype: 1,
|
||||
Class: 1,
|
||||
Ttl: 3600,
|
||||
Rdlength: 0,
|
||||
},
|
||||
A: net.IPv4(10, 0, 1, 1),
|
||||
}
|
||||
rr2 := dns.A{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: dns.Fqdn("server2.example.com"),
|
||||
Rrtype: 1,
|
||||
Class: 1,
|
||||
Ttl: 3600,
|
||||
Rdlength: 0,
|
||||
},
|
||||
A: net.IPv4(10, 0, 1, 2),
|
||||
}
|
||||
rr3 := dns.A{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: dns.Fqdn("server3.example.com"),
|
||||
Rrtype: 1,
|
||||
Class: 1,
|
||||
Ttl: 3600,
|
||||
Rdlength: 0,
|
||||
},
|
||||
A: net.IPv4(10, 0, 1, 3),
|
||||
}
|
||||
rr4 := dns.A{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: dns.Fqdn("server4.example.com"),
|
||||
Rrtype: 1,
|
||||
Class: 1,
|
||||
Ttl: 3600,
|
||||
Rdlength: 0,
|
||||
},
|
||||
A: net.IPv4(10, 0, 1, 4),
|
||||
}
|
||||
tree := Tree{
|
||||
Root: nil,
|
||||
Count: 0,
|
||||
}
|
||||
tree.Insert(&rr1)
|
||||
tree.Insert(&rr2)
|
||||
tree.Insert(&rr3)
|
||||
tree.Insert(&rr4)
|
||||
|
||||
/**
|
||||
build a LLRB tree, the height of the tree is 3, look like:
|
||||
|
||||
server2.example.com.
|
||||
/ \
|
||||
server1.example.com. server4.example.com.
|
||||
/
|
||||
server3.example.com.
|
||||
|
||||
*/
|
||||
|
||||
f, err := os.Create("tmp")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
//Redirect the printed results to a tmp file for later comparison
|
||||
os.Stdout = f
|
||||
|
||||
tree.Print()
|
||||
/**
|
||||
server2.example.com.
|
||||
server1.example.com. server4.example.com.
|
||||
server3.example.com.
|
||||
*/
|
||||
|
||||
buf := make([]byte, 256)
|
||||
f.Seek(0, 0)
|
||||
_, er := f.Read(buf)
|
||||
if er != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
height := strings.Count(string(buf), ". \n")
|
||||
//Compare the height of the print with the actual height of the tree
|
||||
if height != 3 {
|
||||
f.Close()
|
||||
os.Remove("tmp")
|
||||
t.Fatal("The number of rows is inconsistent with the actual number of rows in the tree itself.")
|
||||
}
|
||||
f.Close()
|
||||
os.Remove("tmp")
|
||||
}
|
|
@ -78,7 +78,9 @@ forward FROM TO... {
|
|||
* `tls_servername` **NAME** allows you to set a server name in the TLS configuration; for instance 9.9.9.9
|
||||
needs this to be set to `dns.quad9.net`. Multiple upstreams are still allowed in this scenario,
|
||||
but they have to use the same `tls_servername`. E.g. mixing 9.9.9.9 (QuadDNS) with 1.1.1.1
|
||||
(Cloudflare) will not work.
|
||||
(Cloudflare) will not work. Using TLS forwarding but not setting `tls_servername` results in anyone
|
||||
being able to man-in-the-middle your connection to the DNS server you are forwarding to. Because of this,
|
||||
it is strongly recommended to set this value when using TLS forwarding.
|
||||
* `policy` specifies the policy to use for selecting upstream servers. The default is `random`.
|
||||
* `random` is a policy that implements random upstream selection.
|
||||
* `round_robin` is a policy that selects hosts based on round robin ordering.
|
||||
|
|
|
@ -97,6 +97,13 @@ func (p *Proxy) Connect(ctx context.Context, state request.Request, opts options
|
|||
}
|
||||
|
||||
pc.c.SetWriteDeadline(time.Now().Add(maxTimeout))
|
||||
// records the origin Id before upstream.
|
||||
originId := state.Req.Id
|
||||
state.Req.Id = dns.Id()
|
||||
defer func() {
|
||||
state.Req.Id = originId
|
||||
}()
|
||||
|
||||
if err := pc.c.WriteMsg(state.Req); err != nil {
|
||||
pc.c.Close() // not giving it back
|
||||
if err == io.EOF && cached {
|
||||
|
@ -114,6 +121,10 @@ func (p *Proxy) Connect(ctx context.Context, state request.Request, opts options
|
|||
if err == io.EOF && cached {
|
||||
return nil, ErrCachedClosed
|
||||
}
|
||||
// recovery the origin Id after upstream.
|
||||
if ret != nil {
|
||||
ret.Id = originId
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
// drop out-of-order responses
|
||||
|
@ -121,6 +132,8 @@ func (p *Proxy) Connect(ctx context.Context, state request.Request, opts options
|
|||
break
|
||||
}
|
||||
}
|
||||
// recovery the origin Id after upstream.
|
||||
ret.Id = originId
|
||||
|
||||
p.transport.Yield(pc)
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/miekg/dns"
|
||||
ot "github.com/opentracing/opentracing-go"
|
||||
otext "github.com/opentracing/opentracing-go/ext"
|
||||
)
|
||||
|
||||
var log = clog.NewWithPlugin("forward")
|
||||
|
@ -117,6 +118,7 @@ func (f *Forward) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
|
|||
|
||||
if span != nil {
|
||||
child = span.Tracer().StartSpan("connect", ot.ChildOf(span.Context()))
|
||||
otext.PeerAddress.Set(child, proxy.addr)
|
||||
ctx = ot.ContextWithSpan(ctx, child)
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,13 @@ func parseStanza(c *caddy.Controller) (*Forward, error) {
|
|||
if !c.Args(&f.from) {
|
||||
return f, c.ArgErr()
|
||||
}
|
||||
f.from = plugin.Host(f.from).Normalize()[0] // there can only be one here, won't work with non-octet reverse
|
||||
origFrom := f.from
|
||||
zones := plugin.Host(f.from).NormalizeExact()
|
||||
f.from = zones[0] // there can only be one here, won't work with non-octet reverse
|
||||
|
||||
if len(zones) > 1 {
|
||||
log.Warningf("Unsupported CIDR notation: '%s' expands to multiple zones. Using only '%s'.", origFrom, f.from)
|
||||
}
|
||||
|
||||
to := c.RemainingArgs()
|
||||
if len(to) == 0 {
|
||||
|
@ -151,7 +157,7 @@ func parseBlock(c *caddy.Controller, f *Forward) error {
|
|||
return c.ArgErr()
|
||||
}
|
||||
for i := 0; i < len(ignore); i++ {
|
||||
f.ignored = append(f.ignored, plugin.Host(ignore[i]).Normalize()...)
|
||||
f.ignored = append(f.ignored, plugin.Host(ignore[i]).NormalizeExact()...)
|
||||
}
|
||||
case "max_fails":
|
||||
if !c.NextArg() {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package forward
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
@ -125,7 +124,7 @@ func TestSetupTLS(t *testing.T) {
|
|||
|
||||
func TestSetupResolvconf(t *testing.T) {
|
||||
const resolv = "resolv.conf"
|
||||
if err := ioutil.WriteFile(resolv,
|
||||
if err := os.WriteFile(resolv,
|
||||
[]byte(`nameserver 10.10.255.252
|
||||
nameserver 10.10.255.253`), 0666); err != nil {
|
||||
t.Fatalf("Failed to write resolv.conf file: %s", err)
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
# geoip
|
||||
|
||||
## Name
|
||||
*geoip* - Lookup maxmind geoip2 databases using the client IP, then add associated geoip data to the context request.
|
||||
|
||||
## Description
|
||||
The *geoip* plugin add geo location data associated with the client IP, it allows you to configure a [geoIP2 maxmind database](https://dev.maxmind.com/geoip/docs/databases) to add the geo location data associated with the IP address.
|
||||
|
||||
The data is added leveraging the *metadata* plugin, values can then be retrieved using it as well, for example:
|
||||
|
||||
```go
|
||||
import (
|
||||
"strconv"
|
||||
"github.com/coredns/coredns/plugin/metadata"
|
||||
)
|
||||
// ...
|
||||
if getLongitude := metadata.ValueFunc(ctx, "geoip/longitude"); getLongitude != nil {
|
||||
if longitude, err := strconv.ParseFloat(getLongitude(), 64); err == nil {
|
||||
// Do something useful with longitude.
|
||||
}
|
||||
} else {
|
||||
// The metadata label geoip/longitude for some reason, was not set.
|
||||
}
|
||||
// ...
|
||||
```
|
||||
|
||||
## Databases
|
||||
The supported databases use city schema such as `City` and `Enterprise`. Other databases types with different schemas are not supported yet.
|
||||
|
||||
You can download a [free and public City database](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data).
|
||||
|
||||
## Syntax
|
||||
```txt
|
||||
geoip [DBFILE]
|
||||
```
|
||||
* **DBFILE** the mmdb database file path.
|
||||
|
||||
## Examples
|
||||
The following configuration configures the `City` database.
|
||||
```txt
|
||||
. {
|
||||
geoip /opt/geoip2/db/GeoLite2-City.mmdb
|
||||
metadata # Note that metadata plugin must be enabled as well.
|
||||
}
|
||||
```
|
||||
|
||||
## Metadata Labels
|
||||
A limited set of fields will be exported as labels, all values are stored using strings **regardless of their underlying value type**, and therefore you may have to convert it back to its original type, note that numeric values are always represented in base 10.
|
||||
|
||||
| Label | Type | Example | Description
|
||||
| :----------------------------------- | :-------- | :-------------- | :------------------
|
||||
| `geoip/city/name` | `string` | `Cambridge` | Then city name in English language.
|
||||
| `geoip/country/code` | `string` | `GB` | Country [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1) code.
|
||||
| `geoip/country/name` | `string` | `United Kingdom` | The country name in English language.
|
||||
| `geoip/country/is_in_european_union` | `bool` | `false` | Either `true` or `false`.
|
||||
| `geoip/continent/code` | `string` | `EU` | See [Continent codes](#ContinentCodes).
|
||||
| `geoip/continent/name` | `string` | `Europe` | The continent name in English language.
|
||||
| `geoip/latitude` | `float64` | `52.2242` | Base 10, max available precision.
|
||||
| `geoip/longitude` | `float64` | `0.1315` | Base 10, max available precision.
|
||||
| `geoip/timezone` | `string` | `Europe/London` | The timezone.
|
||||
| `geoip/postalcode` | `string` | `CB4` | The postal code.
|
||||
|
||||
## Continent Codes
|
||||
|
||||
| Value | Continent (EN) |
|
||||
| :---- | :------------- |
|
||||
| AF | Africa |
|
||||
| AN | Antarctica |
|
||||
| AS | Asia |
|
||||
| EU | Europe |
|
||||
| NA | North America |
|
||||
| OC | Oceania |
|
||||
| SA | South America |
|
|
@ -0,0 +1,58 @@
|
|||
package geoip
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"coredns/plugin/metadata"
|
||||
|
||||
"github.com/oschwald/geoip2-golang"
|
||||
)
|
||||
|
||||
const defaultLang = "en"
|
||||
|
||||
func (g GeoIP) setCityMetadata(ctx context.Context, data *geoip2.City) {
|
||||
// Set labels for city, country and continent names.
|
||||
cityName := data.City.Names[defaultLang]
|
||||
metadata.SetValueFunc(ctx, pluginName+"/city/name", func() string {
|
||||
return cityName
|
||||
})
|
||||
countryName := data.Country.Names[defaultLang]
|
||||
metadata.SetValueFunc(ctx, pluginName+"/country/name", func() string {
|
||||
return countryName
|
||||
})
|
||||
continentName := data.Continent.Names[defaultLang]
|
||||
metadata.SetValueFunc(ctx, pluginName+"/continent/name", func() string {
|
||||
return continentName
|
||||
})
|
||||
|
||||
countryCode := data.Country.IsoCode
|
||||
metadata.SetValueFunc(ctx, pluginName+"/country/code", func() string {
|
||||
return countryCode
|
||||
})
|
||||
isInEurope := strconv.FormatBool(data.Country.IsInEuropeanUnion)
|
||||
metadata.SetValueFunc(ctx, pluginName+"/country/is_in_european_union", func() string {
|
||||
return isInEurope
|
||||
})
|
||||
continentCode := data.Continent.Code
|
||||
metadata.SetValueFunc(ctx, pluginName+"/continent/code", func() string {
|
||||
return continentCode
|
||||
})
|
||||
|
||||
latitude := strconv.FormatFloat(float64(data.Location.Latitude), 'f', -1, 64)
|
||||
metadata.SetValueFunc(ctx, pluginName+"/latitude", func() string {
|
||||
return latitude
|
||||
})
|
||||
longitude := strconv.FormatFloat(float64(data.Location.Longitude), 'f', -1, 64)
|
||||
metadata.SetValueFunc(ctx, pluginName+"/longitude", func() string {
|
||||
return longitude
|
||||
})
|
||||
timeZone := data.Location.TimeZone
|
||||
metadata.SetValueFunc(ctx, pluginName+"/timezone", func() string {
|
||||
return timeZone
|
||||
})
|
||||
postalCode := data.Postal.Code
|
||||
metadata.SetValueFunc(ctx, pluginName+"/postalcode", func() string {
|
||||
return postalCode
|
||||
})
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
// Package geoip implements a max mind database plugin.
|
||||
package geoip
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
|
||||
"coredns/plugin"
|
||||
clog "coredns/plugin/pkg/log"
|
||||
"coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/oschwald/geoip2-golang"
|
||||
)
|
||||
|
||||
var log = clog.NewWithPlugin(pluginName)
|
||||
|
||||
// GeoIP is a plugin that add geo location data to the request context by looking up a maxmind
|
||||
// geoIP2 database, and which data can be later consumed by other middlewares.
|
||||
type GeoIP struct {
|
||||
Next plugin.Handler
|
||||
db db
|
||||
}
|
||||
|
||||
type db struct {
|
||||
*geoip2.Reader
|
||||
// provides defines the schemas that can be obtained by querying this database, by using
|
||||
// bitwise operations.
|
||||
provides int
|
||||
}
|
||||
|
||||
const (
|
||||
city = 1 << iota
|
||||
)
|
||||
|
||||
var probingIP = net.ParseIP("127.0.0.1")
|
||||
|
||||
func newGeoIP(dbPath string) (*GeoIP, error) {
|
||||
reader, err := geoip2.Open(dbPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open database file: %v", err)
|
||||
}
|
||||
db := db{Reader: reader}
|
||||
schemas := []struct {
|
||||
provides int
|
||||
name string
|
||||
validate func() error
|
||||
}{
|
||||
{name: "city", provides: city, validate: func() error { _, err := reader.City(probingIP); return err }},
|
||||
}
|
||||
// Query the database to figure out the database type.
|
||||
for _, schema := range schemas {
|
||||
if err := schema.validate(); err != nil {
|
||||
// If we get an InvalidMethodError then we know this database does not provide that schema.
|
||||
if _, ok := err.(geoip2.InvalidMethodError); !ok {
|
||||
return nil, fmt.Errorf("unexpected failure looking up database %q schema %q: %v", filepath.Base(dbPath), schema.name, err)
|
||||
}
|
||||
} else {
|
||||
db.provides = db.provides | schema.provides
|
||||
}
|
||||
}
|
||||
|
||||
if db.provides&city == 0 {
|
||||
return nil, fmt.Errorf("database does not provide city schema")
|
||||
}
|
||||
|
||||
return &GeoIP{db: db}, nil
|
||||
}
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (g GeoIP) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
return plugin.NextOrFailure(pluginName, g.Next, ctx, w, r)
|
||||
}
|
||||
|
||||
// Metadata implements the metadata.Provider Interface in the metadata plugin, and is used to store
|
||||
// the data associated with the source IP of every request.
|
||||
func (g GeoIP) Metadata(ctx context.Context, state request.Request) context.Context {
|
||||
srcIP := net.ParseIP(state.IP())
|
||||
|
||||
switch {
|
||||
case g.db.provides&city == city:
|
||||
data, err := g.db.City(srcIP)
|
||||
if err != nil {
|
||||
log.Debugf("Setting up metadata failed due to database lookup error: %v", err)
|
||||
return ctx
|
||||
}
|
||||
g.setCityMetadata(ctx, data)
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Name implements the Handler interface.
|
||||
func (g GeoIP) Name() string { return pluginName }
|
|
@ -0,0 +1,61 @@
|
|||
package geoip
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"coredns/plugin/metadata"
|
||||
"coredns/plugin/test"
|
||||
"coredns/request"
|
||||
)
|
||||
|
||||
func TestMetadata(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
dbPath string
|
||||
label string
|
||||
expectedValue string
|
||||
}{
|
||||
{cityDBPath, "geoip/city/name", "Cambridge"},
|
||||
|
||||
{cityDBPath, "geoip/country/code", "GB"},
|
||||
{cityDBPath, "geoip/country/name", "United Kingdom"},
|
||||
// is_in_european_union is set to true only to work around bool zero value, and test is really being set.
|
||||
{cityDBPath, "geoip/country/is_in_european_union", "true"},
|
||||
|
||||
{cityDBPath, "geoip/continent/code", "EU"},
|
||||
{cityDBPath, "geoip/continent/name", "Europe"},
|
||||
|
||||
{cityDBPath, "geoip/latitude", "52.2242"},
|
||||
{cityDBPath, "geoip/longitude", "0.1315"},
|
||||
{cityDBPath, "geoip/timezone", "Europe/London"},
|
||||
{cityDBPath, "geoip/postalcode", "CB4"},
|
||||
}
|
||||
|
||||
for i, _test := range tests {
|
||||
geoIP, err := newGeoIP(_test.dbPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Test %d: unable to create geoIP plugin: %v", i, err)
|
||||
}
|
||||
state := request.Request{
|
||||
W: &test.ResponseWriter{RemoteIP: "81.2.69.142"}, // This IP should be be part of the CDIR address range used to create the database fixtures.
|
||||
}
|
||||
ctx := metadata.ContextWithMetadata(context.Background())
|
||||
rCtx := geoIP.Metadata(ctx, state)
|
||||
if fmt.Sprintf("%p", ctx) != fmt.Sprintf("%p", rCtx) {
|
||||
t.Errorf("Test %d: returned context is expected to be the same one passed in the Metadata function", i)
|
||||
}
|
||||
|
||||
fn := metadata.ValueFunc(ctx, _test.label)
|
||||
if fn == nil {
|
||||
t.Errorf("Test %d: label %q not set in metadata plugin context", i, _test.label)
|
||||
continue
|
||||
}
|
||||
value := fn()
|
||||
if value != _test.expectedValue {
|
||||
t.Errorf("Test %d: expected value for label %q should be %q, got %q instead",
|
||||
i, _test.label, _test.expectedValue, value)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package geoip
|
||||
|
||||
import (
|
||||
"coredns/caddy"
|
||||
"coredns/core/dnsserver"
|
||||
"coredns/plugin"
|
||||
)
|
||||
|
||||
const pluginName = "geoip"
|
||||
|
||||
func init() { plugin.Register(pluginName, setup) }
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
geoip, err := geoipParse(c)
|
||||
if err != nil {
|
||||
return plugin.Error(pluginName, err)
|
||||
}
|
||||
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
geoip.Next = next
|
||||
return geoip
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func geoipParse(c *caddy.Controller) (*GeoIP, error) {
|
||||
var dbPath string
|
||||
|
||||
for c.Next() {
|
||||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
if dbPath != "" {
|
||||
return nil, c.Errf("configuring multiple databases is not supported")
|
||||
}
|
||||
dbPath = c.Val()
|
||||
// There shouldn't be any more arguments.
|
||||
if len(c.RemainingArgs()) != 0 {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
// The plugin should not have any config block.
|
||||
if c.NextBlock() {
|
||||
return nil, c.Err("unexpected config block")
|
||||
}
|
||||
}
|
||||
|
||||
geoIP, err := newGeoIP(dbPath)
|
||||
if err != nil {
|
||||
return geoIP, c.Err(err.Error())
|
||||
}
|
||||
return geoIP, nil
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package geoip
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"coredns/caddy"
|
||||
"coredns/core/dnsserver"
|
||||
)
|
||||
|
||||
var (
|
||||
fixturesDir = "./testdata"
|
||||
cityDBPath = filepath.Join(fixturesDir, "GeoLite2-City.mmdb")
|
||||
unknownDBPath = filepath.Join(fixturesDir, "GeoLite2-UnknownDbType.mmdb")
|
||||
)
|
||||
|
||||
func TestProbingIP(t *testing.T) {
|
||||
if probingIP == nil {
|
||||
t.Fatalf("Invalid probing IP: %q", probingIP)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
c := caddy.NewTestController("dns", fmt.Sprintf("%s %s", pluginName, cityDBPath))
|
||||
plugins := dnsserver.GetConfig(c).Plugin
|
||||
if len(plugins) != 0 {
|
||||
t.Fatalf("Expected zero plugins after setup, %d found", len(plugins))
|
||||
}
|
||||
if err := setup(c); err != nil {
|
||||
t.Fatalf("Expected no errors, but got: %v", err)
|
||||
}
|
||||
plugins = dnsserver.GetConfig(c).Plugin
|
||||
if len(plugins) != 1 {
|
||||
t.Fatalf("Expected one plugin after setup, %d found", len(plugins))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeoIPParse(t *testing.T) {
|
||||
c := caddy.NewTestController("dns", fmt.Sprintf("%s %s", pluginName, cityDBPath))
|
||||
if err := setup(c); err != nil {
|
||||
t.Fatalf("Expected no errors, but got: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
shouldErr bool
|
||||
config string
|
||||
expectedErr string
|
||||
expectedDBType int
|
||||
}{
|
||||
// Valid
|
||||
{false, fmt.Sprintf("%s %s\n", pluginName, cityDBPath), "", city},
|
||||
|
||||
// Invalid
|
||||
{true, pluginName, "Wrong argument count", 0},
|
||||
{true, fmt.Sprintf("%s %s {\n\tlanguages en fr es zh-CN\n}\n", pluginName, cityDBPath), "unexpected config block", 0},
|
||||
{true, fmt.Sprintf("%s %s\n%s %s\n", pluginName, cityDBPath, pluginName, cityDBPath), "configuring multiple databases is not supported", 0},
|
||||
{true, fmt.Sprintf("%s 1 2 3", pluginName), "Wrong argument count", 0},
|
||||
{true, fmt.Sprintf("%s { }", pluginName), "Error during parsing", 0},
|
||||
{true, fmt.Sprintf("%s /dbpath { city }", pluginName), "unexpected config block", 0},
|
||||
{true, fmt.Sprintf("%s /invalidPath\n", pluginName), "failed to open database file: open /invalidPath: no such file or directory", 0},
|
||||
{true, fmt.Sprintf("%s %s\n", pluginName, unknownDBPath), "reader does not support the \"UnknownDbType\" database type", 0},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
c := caddy.NewTestController("dns", test.config)
|
||||
geoIP, err := geoipParse(c)
|
||||
|
||||
if test.shouldErr && err == nil {
|
||||
t.Errorf("Test %d: expected error but found none for input %s", i, test.config)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if !test.shouldErr {
|
||||
t.Errorf("Test %d: expected no error but found one for input %s, got: %v", i, test.config, err)
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), test.expectedErr) {
|
||||
t.Errorf("Test %d: expected error to contain: %v, found error: %v, input: %s", i, test.expectedErr, err, test.config)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if geoIP.db.Reader == nil {
|
||||
t.Errorf("Test %d: after parsing database reader should be initialized", i)
|
||||
}
|
||||
|
||||
if geoIP.db.provides&test.expectedDBType == 0 {
|
||||
t.Errorf("Test %d: expected db type %d not found, database file provides %d", i, test.expectedDBType, geoIP.db.provides)
|
||||
}
|
||||
}
|
||||
|
||||
// Set nil probingIP to test unexpected validate error()
|
||||
defer func(ip net.IP) { probingIP = ip }(probingIP)
|
||||
probingIP = nil
|
||||
|
||||
c = caddy.NewTestController("dns", fmt.Sprintf("%s %s\n", pluginName, cityDBPath))
|
||||
_, err := geoipParse(c)
|
||||
if err != nil {
|
||||
expectedErr := "unexpected failure looking up database"
|
||||
if !strings.Contains(err.Error(), expectedErr) {
|
||||
t.Errorf("expected error to contain: %s", expectedErr)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("with a nil probingIP test is expected to fail")
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
|
@ -0,0 +1,112 @@
|
|||
# testdata
|
||||
This directory contains mmdb database files used during the testing of this plugin.
|
||||
|
||||
# Create mmdb database files
|
||||
If you need to change them to add a new value, or field the best is to recreate them, the code snipped used to create them initially is provided next.
|
||||
|
||||
```golang
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/maxmind/mmdbwriter"
|
||||
"github.com/maxmind/mmdbwriter/inserter"
|
||||
"github.com/maxmind/mmdbwriter/mmdbtype"
|
||||
)
|
||||
|
||||
const cdir = "81.2.69.142/32"
|
||||
|
||||
// Create new mmdb database fixtures in this directory.
|
||||
func main() {
|
||||
createCityDB("GeoLite2-City.mmdb", "DBIP-City-Lite")
|
||||
// Create unkwnon database type.
|
||||
createCityDB("GeoLite2-UnknownDbType.mmdb", "UnknownDbType")
|
||||
}
|
||||
|
||||
func createCityDB(dbName, dbType string) {
|
||||
// Load a database writer.
|
||||
writer, err := mmdbwriter.New(mmdbwriter.Options{DatabaseType: dbType})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Define and insert the new data.
|
||||
_, ip, err := net.ParseCIDR(cdir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// TODO(snebel29): Find an alternative location in Europe Union.
|
||||
record := mmdbtype.Map{
|
||||
"city": mmdbtype.Map{
|
||||
"geoname_id": mmdbtype.Uint64(2653941),
|
||||
"names": mmdbtype.Map{
|
||||
"en": mmdbtype.String("Cambridge"),
|
||||
"es": mmdbtype.String("Cambridge"),
|
||||
},
|
||||
},
|
||||
"continent": mmdbtype.Map{
|
||||
"code": mmdbtype.String("EU"),
|
||||
"geoname_id": mmdbtype.Uint64(6255148),
|
||||
"names": mmdbtype.Map{
|
||||
"en": mmdbtype.String("Europe"),
|
||||
"es": mmdbtype.String("Europa"),
|
||||
},
|
||||
},
|
||||
"country": mmdbtype.Map{
|
||||
"iso_code": mmdbtype.String("GB"),
|
||||
"geoname_id": mmdbtype.Uint64(2635167),
|
||||
"names": mmdbtype.Map{
|
||||
"en": mmdbtype.String("United Kingdom"),
|
||||
"es": mmdbtype.String("Reino Unido"),
|
||||
},
|
||||
"is_in_european_union": mmdbtype.Bool(true),
|
||||
},
|
||||
"location": mmdbtype.Map{
|
||||
"accuracy_radius": mmdbtype.Uint16(200),
|
||||
"latitude": mmdbtype.Float64(52.2242),
|
||||
"longitude": mmdbtype.Float64(0.1315),
|
||||
"metro_code": mmdbtype.Uint64(0),
|
||||
"time_zone": mmdbtype.String("Europe/London"),
|
||||
},
|
||||
"postal": mmdbtype.Map{
|
||||
"code": mmdbtype.String("CB4"),
|
||||
},
|
||||
"registered_country": mmdbtype.Map{
|
||||
"iso_code": mmdbtype.String("GB"),
|
||||
"geoname_id": mmdbtype.Uint64(2635167),
|
||||
"names": mmdbtype.Map{"en": mmdbtype.String("United Kingdom")},
|
||||
"is_in_european_union": mmdbtype.Bool(false),
|
||||
},
|
||||
"subdivisions": mmdbtype.Slice{
|
||||
mmdbtype.Map{
|
||||
"iso_code": mmdbtype.String("ENG"),
|
||||
"geoname_id": mmdbtype.Uint64(6269131),
|
||||
"names": mmdbtype.Map{"en": mmdbtype.String("England")},
|
||||
},
|
||||
mmdbtype.Map{
|
||||
"iso_code": mmdbtype.String("CAM"),
|
||||
"geoname_id": mmdbtype.Uint64(2653940),
|
||||
"names": mmdbtype.Map{"en": mmdbtype.String("Cambridgeshire")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := writer.InsertFunc(ip, inserter.TopLevelMergeWith(record)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Write the DB to the filesystem.
|
||||
fh, err := os.Create(dbName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
_, err = writer.WriteTo(fh)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,7 +1,6 @@
|
|||
package grpc
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
@ -105,7 +104,7 @@ tls
|
|||
|
||||
func TestSetupResolvconf(t *testing.T) {
|
||||
const resolv = "resolv.conf"
|
||||
if err := ioutil.WriteFile(resolv,
|
||||
if err := os.WriteFile(resolv,
|
||||
[]byte(`nameserver 10.10.255.252
|
||||
nameserver 10.10.255.253`), 0666); err != nil {
|
||||
t.Fatalf("Failed to write resolv.conf file: %s", err)
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
# header
|
||||
|
||||
## Name
|
||||
|
||||
*header* - modifies the header for responses.
|
||||
|
||||
## Description
|
||||
|
||||
*header* ensures that the flags are in the desired state for responses. The modifications are made transparently for
|
||||
the client.
|
||||
|
||||
## Syntax
|
||||
|
||||
~~~
|
||||
header {
|
||||
ACTION FLAGS...
|
||||
ACTION FLAGS...
|
||||
}
|
||||
~~~
|
||||
|
||||
* **ACTION** defines the state for DNS message header flags. Actions are evaluated in the order they are defined so last one has the
|
||||
most precedence. Allowed values are:
|
||||
* `set`
|
||||
* `clear`
|
||||
* **FLAGS** are the DNS header flags that will be modified. Current supported flags include:
|
||||
* `aa` - Authoritative(Answer)
|
||||
* `ra` - RecursionAvailable
|
||||
* `rd` - RecursionDesired
|
||||
|
||||
## Examples
|
||||
|
||||
Make sure recursive available `ra` flag is set in all the responses:
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
header {
|
||||
set ra
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Make sure "recursion available" `ra` and "authoritative answer" `aa` flags are set and "recursion desired" is cleared in all responses:
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
header {
|
||||
set ra aa
|
||||
clear rd
|
||||
}
|
||||
}
|
||||
~~~
|
|
@ -0,0 +1,24 @@
|
|||
package header
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"coredns/plugin"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Header modifies dns.MsgHdr in the responses
|
||||
type Header struct {
|
||||
Rules []Rule
|
||||
Next plugin.Handler
|
||||
}
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (h Header) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
wr := ResponseHeaderWriter{ResponseWriter: w, Rules: h.Rules}
|
||||
return plugin.NextOrFailure(h.Name(), h.Next, ctx, &wr, r)
|
||||
}
|
||||
|
||||
// Name implements the plugin.Handler interface.
|
||||
func (h Header) Name() string { return "header" }
|
|
@ -0,0 +1,92 @@
|
|||
package header
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
clog "coredns/plugin/pkg/log"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Supported flags
|
||||
const (
|
||||
authoritative = "aa"
|
||||
recursionAvailable = "ra"
|
||||
recursionDesired = "rd"
|
||||
)
|
||||
|
||||
var log = clog.NewWithPlugin("header")
|
||||
|
||||
// ResponseHeaderWriter is a response writer that allows modifying dns.MsgHdr
|
||||
type ResponseHeaderWriter struct {
|
||||
dns.ResponseWriter
|
||||
Rules []Rule
|
||||
}
|
||||
|
||||
// WriteMsg implements the dns.ResponseWriter interface.
|
||||
func (r *ResponseHeaderWriter) WriteMsg(res *dns.Msg) error {
|
||||
// handle all supported flags
|
||||
for _, rule := range r.Rules {
|
||||
switch rule.Flag {
|
||||
case authoritative:
|
||||
res.Authoritative = rule.State
|
||||
case recursionAvailable:
|
||||
res.RecursionAvailable = rule.State
|
||||
case recursionDesired:
|
||||
res.RecursionDesired = rule.State
|
||||
}
|
||||
}
|
||||
|
||||
return r.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
||||
// Write implements the dns.ResponseWriter interface.
|
||||
func (r *ResponseHeaderWriter) Write(buf []byte) (int, error) {
|
||||
log.Warning("ResponseHeaderWriter called with Write: not ensuring headers")
|
||||
n, err := r.ResponseWriter.Write(buf)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Rule is used to set/clear Flag in dns.MsgHdr
|
||||
type Rule struct {
|
||||
Flag string
|
||||
State bool
|
||||
}
|
||||
|
||||
func newRules(key string, args []string) ([]Rule, error) {
|
||||
if key == "" {
|
||||
return nil, fmt.Errorf("no flag action provided")
|
||||
}
|
||||
|
||||
if len(args) < 1 {
|
||||
return nil, fmt.Errorf("invalid length for flags, at least one should be provided")
|
||||
}
|
||||
|
||||
var state bool
|
||||
action := strings.ToLower(key)
|
||||
switch action {
|
||||
case "set":
|
||||
state = true
|
||||
case "clear":
|
||||
state = false
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown flag action=%s, should be set or clear", action)
|
||||
}
|
||||
|
||||
var rules []Rule
|
||||
for _, arg := range args {
|
||||
flag := strings.ToLower(arg)
|
||||
switch flag {
|
||||
case authoritative:
|
||||
case recursionAvailable:
|
||||
case recursionDesired:
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown/unsupported flag=%s", flag)
|
||||
}
|
||||
rule := Rule{Flag: flag, State: state}
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package header
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"coredns/plugin"
|
||||
"coredns/plugin/pkg/dnstest"
|
||||
"coredns/plugin/test"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func TestHeader(t *testing.T) {
|
||||
wr := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||
next := plugin.HandlerFunc(func(ctx context.Context, writer dns.ResponseWriter, msg *dns.Msg) (int, error) {
|
||||
writer.WriteMsg(msg)
|
||||
return dns.RcodeSuccess, nil
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
handler plugin.Handler
|
||||
got func(msg *dns.Msg) bool
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
handler: Header{
|
||||
Rules: []Rule{{Flag: recursionAvailable, State: true}},
|
||||
Next: next,
|
||||
},
|
||||
got: func(msg *dns.Msg) bool {
|
||||
return msg.RecursionAvailable
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
handler: Header{
|
||||
Rules: []Rule{{Flag: recursionAvailable, State: true}},
|
||||
Next: next,
|
||||
},
|
||||
got: func(msg *dns.Msg) bool {
|
||||
return msg.RecursionAvailable
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
handler: Header{
|
||||
Rules: []Rule{{Flag: recursionDesired, State: true}},
|
||||
Next: next,
|
||||
},
|
||||
got: func(msg *dns.Msg) bool {
|
||||
return msg.RecursionDesired
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
handler: Header{
|
||||
Rules: []Rule{{Flag: authoritative, State: true}},
|
||||
Next: next,
|
||||
},
|
||||
got: func(msg *dns.Msg) bool {
|
||||
return msg.Authoritative
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
m := new(dns.Msg)
|
||||
|
||||
_, err := test.handler.ServeDNS(context.TODO(), wr, m)
|
||||
if err != nil {
|
||||
t.Errorf("Test %d: Expected no error, but got %s", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if test.got(m) != test.expected {
|
||||
t.Errorf("Test %d: Expected flag state=%t, but got %t", i, test.expected, test.got(m))
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package header
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"coredns/caddy"
|
||||
"coredns/core/dnsserver"
|
||||
"coredns/plugin"
|
||||
)
|
||||
|
||||
func init() { plugin.Register("header", setup) }
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
rules, err := parse(c)
|
||||
if err != nil {
|
||||
return plugin.Error("header", err)
|
||||
}
|
||||
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
return Header{
|
||||
Rules: rules,
|
||||
Next: next,
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parse(c *caddy.Controller) ([]Rule, error) {
|
||||
for c.Next() {
|
||||
var all []Rule
|
||||
for c.NextBlock() {
|
||||
v := c.Val()
|
||||
args := c.RemainingArgs()
|
||||
// set up rules
|
||||
rules, err := newRules(v, args)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("seting up rule: %w", err)
|
||||
}
|
||||
all = append(all, rules...)
|
||||
}
|
||||
|
||||
// return combined rules
|
||||
if len(all) > 0 {
|
||||
return all, nil
|
||||
}
|
||||
}
|
||||
return nil, c.ArgErr()
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package header
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"coredns/caddy"
|
||||
)
|
||||
|
||||
func TestSetupHeader(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
shouldErr bool
|
||||
expectedErrContent string
|
||||
}{
|
||||
{`header {}`, true, "Wrong argument count or unexpected line ending after"},
|
||||
{`header {
|
||||
set
|
||||
}`, true, "invalid length for flags, at least one should be provided"},
|
||||
{`header {
|
||||
foo
|
||||
}`, true, "invalid length for flags, at least one should be provided"},
|
||||
{`header {
|
||||
foo bar
|
||||
}`, true, "unknown flag action=foo, should be set or clear"},
|
||||
{`header {
|
||||
set ra
|
||||
}`, false, ""},
|
||||
{`header {
|
||||
set ra aa
|
||||
clear rd
|
||||
}`, false, ""},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
c := caddy.NewTestController("dns", test.input)
|
||||
err := setup(c)
|
||||
|
||||
if test.shouldErr && err == nil {
|
||||
t.Errorf("Test %d: Expected error but found none for input %s", i, test.input)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if !test.shouldErr {
|
||||
t.Errorf("Test %d: Expected no error but found one for input %s. Error was: %v", i, test.input, err)
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), test.expectedErrContent) {
|
||||
t.Errorf("Test %d: Expected error to contain: %v, found error: %v, input: %s", i, test.expectedErrContent, err, test.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
# health
|
||||
|
||||
## Name
|
||||
|
||||
*health* - enables a health check endpoint.
|
||||
|
||||
## Description
|
||||
|
||||
Enabled process wide health endpoint. When CoreDNS is up and running this returns a 200 OK HTTP
|
||||
status code. The health is exported, by default, on port 8080/health.
|
||||
|
||||
## Syntax
|
||||
|
||||
~~~
|
||||
health [ADDRESS]
|
||||
~~~
|
||||
|
||||
Optionally takes an address; the default is `:8080`. The health path is fixed to `/health`. The
|
||||
health endpoint returns a 200 response code and the word "OK" when this server is healthy.
|
||||
|
||||
An extra option can be set with this extended syntax:
|
||||
|
||||
~~~
|
||||
health [ADDRESS] {
|
||||
lameduck DURATION
|
||||
}
|
||||
~~~
|
||||
|
||||
* Where `lameduck` will delay shutdown for **DURATION**. /health will still answer 200 OK.
|
||||
Note: The *ready* plugin will not answer OK while CoreDNS is in lame duck mode prior to shutdown.
|
||||
|
||||
If you have multiple Server Blocks, *health* can only be enabled in one of them (as it is process
|
||||
wide). If you really need multiple endpoints, you must run health endpoints on different ports:
|
||||
|
||||
~~~ corefile
|
||||
com {
|
||||
whoami
|
||||
health :8080
|
||||
}
|
||||
|
||||
net {
|
||||
erratic
|
||||
health :8081
|
||||
}
|
||||
~~~
|
||||
|
||||
Doing this is supported but both endpoints ":8080" and ":8081" will export the exact same health.
|
||||
|
||||
## Metrics
|
||||
|
||||
If monitoring is enabled (via the *prometheus* plugin) then the following metric is exported:
|
||||
|
||||
* `coredns_health_request_duration_seconds{}` - duration to process a HTTP query to the local
|
||||
`/health` endpoint. As this a local operation it should be fast. A (large) increase in this
|
||||
duration indicates the CoreDNS process is having trouble keeping up with its query load.
|
||||
|
||||
Note that this metric *does not* have a `server` label, because being overloaded is a symptom of
|
||||
the running process, *not* a specific server.
|
||||
|
||||
## Examples
|
||||
|
||||
Run another health endpoint on http://localhost:8091.
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
health localhost:8091
|
||||
}
|
||||
~~~
|
||||
|
||||
Set a lame duck duration of 1 second:
|
||||
|
||||
~~~ corefile
|
||||
. {
|
||||
health localhost:8092 {
|
||||
lameduck 1s
|
||||
}
|
||||
}
|
||||
~~~
|
|
@ -1,69 +0,0 @@
|
|||
// Package health implements an HTTP handler that responds to health checks.
|
||||
package health
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
clog "coredns/plugin/pkg/log"
|
||||
"coredns/plugin/pkg/reuseport"
|
||||
)
|
||||
|
||||
var log = clog.NewWithPlugin("health")
|
||||
|
||||
// Health implements healthchecks by exporting a HTTP endpoint.
|
||||
type health struct {
|
||||
Addr string
|
||||
lameduck time.Duration
|
||||
|
||||
ln net.Listener
|
||||
nlSetup bool
|
||||
mux *http.ServeMux
|
||||
|
||||
stop chan bool
|
||||
}
|
||||
|
||||
func (h *health) OnStartup() error {
|
||||
if h.Addr == "" {
|
||||
h.Addr = ":8080"
|
||||
}
|
||||
h.stop = make(chan bool)
|
||||
ln, err := reuseport.Listen("tcp", h.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.ln = ln
|
||||
h.mux = http.NewServeMux()
|
||||
h.nlSetup = true
|
||||
|
||||
h.mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
// We're always healthy.
|
||||
w.WriteHeader(http.StatusOK)
|
||||
io.WriteString(w, http.StatusText(http.StatusOK))
|
||||
})
|
||||
|
||||
go func() { http.Serve(h.ln, h.mux) }()
|
||||
go func() { h.overloaded() }()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *health) OnFinalShutdown() error {
|
||||
if !h.nlSetup {
|
||||
return nil
|
||||
}
|
||||
|
||||
if h.lameduck > 0 {
|
||||
log.Infof("Going into lameduck mode for %s", h.lameduck)
|
||||
time.Sleep(h.lameduck)
|
||||
}
|
||||
|
||||
h.ln.Close()
|
||||
|
||||
h.nlSetup = false
|
||||
close(h.stop)
|
||||
return nil
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package health
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestHealth(t *testing.T) {
|
||||
h := &health{Addr: ":0", stop: make(chan bool)}
|
||||
|
||||
if err := h.OnStartup(); err != nil {
|
||||
t.Fatalf("Unable to startup the health server: %v", err)
|
||||
}
|
||||
defer h.OnFinalShutdown()
|
||||
|
||||
address := fmt.Sprintf("http://%s%s", h.ln.Addr().String(), "/health")
|
||||
|
||||
response, err := http.Get(address)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to query %s: %v", address, err)
|
||||
}
|
||||
if response.StatusCode != 200 {
|
||||
t.Errorf("Invalid status code: expecting '200', got '%d'", response.StatusCode)
|
||||
}
|
||||
content, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to get response body from %s: %v", address, err)
|
||||
}
|
||||
response.Body.Close()
|
||||
|
||||
if string(content) != http.StatusText(http.StatusOK) {
|
||||
t.Errorf("Invalid response body: expecting 'OK', got '%s'", string(content))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthLameduck(t *testing.T) {
|
||||
h := &health{Addr: ":0", stop: make(chan bool), lameduck: 250 * time.Millisecond}
|
||||
|
||||
if err := h.OnStartup(); err != nil {
|
||||
t.Fatalf("Unable to startup the health server: %v", err)
|
||||
}
|
||||
|
||||
h.OnFinalShutdown()
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package health
|
||||
|
||||
import clog "coredns/plugin/pkg/log"
|
||||
|
||||
func init() { clog.Discard() }
|
|
@ -1,44 +0,0 @@
|
|||
package health
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
//"coredns/plugin"
|
||||
|
||||
)
|
||||
|
||||
// overloaded queries the health end point and updates a metrics showing how long it took.
|
||||
func (h *health) overloaded() {
|
||||
timeout := time.Duration(3 * time.Second)
|
||||
client := http.Client{
|
||||
Timeout: timeout,
|
||||
}
|
||||
url := "http://" + h.Addr + "/health"
|
||||
tick := time.NewTicker(1 * time.Second)
|
||||
defer tick.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
start := time.Now()
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
//HealthDuration.Observe(timeout.Seconds())
|
||||
log.Warningf("Local health request to %q failed: %s", url, err)
|
||||
continue
|
||||
}
|
||||
resp.Body.Close()
|
||||
elapsed := time.Since(start)
|
||||
//HealthDuration.Observe(elapsed.Seconds())
|
||||
if elapsed > time.Second { // 1s is pretty random, but a *local* scrape taking that long isn't good
|
||||
log.Warningf("Local health request to %q took more than 1s: %s", url, elapsed)
|
||||
}
|
||||
|
||||
case <-h.stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
package health
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"coredns/caddy"
|
||||
"coredns/plugin"
|
||||
)
|
||||
|
||||
func init() { plugin.Register("health", setup) }
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
addr, lame, err := parse(c)
|
||||
if err != nil {
|
||||
return plugin.Error("health", err)
|
||||
}
|
||||
|
||||
h := &health{Addr: addr, stop: make(chan bool), lameduck: lame}
|
||||
|
||||
c.OnStartup(h.OnStartup)
|
||||
c.OnRestart(h.OnFinalShutdown)
|
||||
c.OnFinalShutdown(h.OnFinalShutdown)
|
||||
c.OnRestartFailed(h.OnStartup)
|
||||
|
||||
// Don't do AddPlugin, as health is not *really* a plugin just a separate webserver running.
|
||||
return nil
|
||||
}
|
||||
|
||||
func parse(c *caddy.Controller) (string, time.Duration, error) {
|
||||
addr := ""
|
||||
dur := time.Duration(0)
|
||||
for c.Next() {
|
||||
args := c.RemainingArgs()
|
||||
|
||||
switch len(args) {
|
||||
case 0:
|
||||
case 1:
|
||||
addr = args[0]
|
||||
if _, _, e := net.SplitHostPort(addr); e != nil {
|
||||
return "", 0, e
|
||||
}
|
||||
default:
|
||||
return "", 0, c.ArgErr()
|
||||
}
|
||||
|
||||
for c.NextBlock() {
|
||||
switch c.Val() {
|
||||
case "lameduck":
|
||||
args := c.RemainingArgs()
|
||||
if len(args) != 1 {
|
||||
return "", 0, c.ArgErr()
|
||||
}
|
||||
l, err := time.ParseDuration(args[0])
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("unable to parse lameduck duration value: '%v' : %v", args[0], err)
|
||||
}
|
||||
dur = l
|
||||
default:
|
||||
return "", 0, c.ArgErr()
|
||||
}
|
||||
}
|
||||
}
|
||||
return addr, dur, nil
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package health
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"coredns/caddy"
|
||||
)
|
||||
|
||||
func TestSetupHealth(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
shouldErr bool
|
||||
}{
|
||||
{`health`, false},
|
||||
{`health localhost:1234`, false},
|
||||
{`health localhost:1234 {
|
||||
lameduck 4s
|
||||
}`, false},
|
||||
{`health bla:a`, false},
|
||||
|
||||
{`health bla`, true},
|
||||
{`health bla bla`, true},
|
||||
{`health localhost:1234 {
|
||||
lameduck a
|
||||
}`, true},
|
||||
{`health localhost:1234 {
|
||||
lamedudk 4
|
||||
} `, true},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
c := caddy.NewTestController("dns", test.input)
|
||||
_, _, err := parse(c)
|
||||
|
||||
if test.shouldErr && err == nil {
|
||||
t.Errorf("Test %d: Expected error but found none for input %s", i, test.input)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if !test.shouldErr {
|
||||
t.Errorf("Test %d: Expected no error but found one for input %s. Error was: %v", i, test.input, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,16 +45,13 @@ var (
|
|||
singlelinehosts = `127.0.0.2 odin`
|
||||
ipv4hosts = `# See https://tools.ietf.org/html/rfc1123.
|
||||
#
|
||||
# The literal IPv4 address parser in the net package is a relaxed
|
||||
# one. It may accept a literal IPv4 address in dotted-decimal notation
|
||||
# with leading zeros such as "001.2.003.4".
|
||||
|
||||
# internet address and host name
|
||||
127.0.0.1 localhost # inline comment separated by tab
|
||||
127.000.000.002 localhost # inline comment separated by space
|
||||
127.0.0.2 localhost # inline comment separated by space
|
||||
|
||||
# internet address, host name and aliases
|
||||
127.000.000.003 localhost localhost.localdomain`
|
||||
127.0.0.3 localhost localhost.localdomain`
|
||||
ipv6hosts = `# See https://tools.ietf.org/html/rfc5952, https://tools.ietf.org/html/rfc4007.
|
||||
|
||||
# internet address and host name
|
||||
|
|
|
@ -61,13 +61,12 @@ func roundRobinShuffle(records []dns.RR) {
|
|||
records[0], records[1] = records[1], records[0]
|
||||
}
|
||||
default:
|
||||
for j := 0; j < l*(int(dns.Id())%4+1); j++ {
|
||||
q := int(dns.Id()) % l
|
||||
p := int(dns.Id()) % l
|
||||
if q == p {
|
||||
p = (p + 1) % l
|
||||
for j := 0; j < l; j++ {
|
||||
p := j + (int(dns.Id()) % (l - j))
|
||||
if j == p {
|
||||
continue
|
||||
}
|
||||
records[q], records[p] = records[p], records[q]
|
||||
records[j], records[p] = records[p], records[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ Each of these logs will be outputted with `log.Infof`, so a typical example look
|
|||
|
||||
~~~ txt
|
||||
[INFO] [::1]:50759 - 29008 "A IN example.org. udp 41 false 4096" NOERROR qr,rd,ra,ad 68 0.037990251s
|
||||
~~~~
|
||||
~~~
|
||||
|
||||
## Examples
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package log
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -240,7 +240,7 @@ func TestLogged(t *testing.T) {
|
|||
}
|
||||
|
||||
func BenchmarkLogged(b *testing.B) {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
log.SetOutput(io.Discard)
|
||||
|
||||
rule := Rule{
|
||||
NameScope: ".",
|
||||
|
|
|
@ -72,12 +72,12 @@ func TestLabelFormat(t *testing.T) {
|
|||
{"plugin/LABEL", true},
|
||||
{"p/LABEL", true},
|
||||
{"plugin/L", true},
|
||||
{"PLUGIN/LABEL/SUB-LABEL", true},
|
||||
// fails
|
||||
{"LABEL", false},
|
||||
{"plugin.LABEL", false},
|
||||
{"/NO-PLUGIN-NOT-ACCEPTED", false},
|
||||
{"ONLY-PLUGIN-NOT-ACCEPTED/", false},
|
||||
{"PLUGIN/LABEL/SUB-LABEL", false},
|
||||
{"/", false},
|
||||
{"//", false},
|
||||
}
|
||||
|
|
|
@ -56,17 +56,13 @@ type Provider interface {
|
|||
// Func is the type of function in the metadata, when called they return the value of the label.
|
||||
type Func func() string
|
||||
|
||||
// IsLabel checks that the provided name is a valid label name, i.e. two words separated by a slash.
|
||||
// IsLabel checks that the provided name is a valid label name, i.e. two or more words separated by a slash.
|
||||
func IsLabel(label string) bool {
|
||||
p := strings.Index(label, "/")
|
||||
if p <= 0 || p >= len(label)-1 {
|
||||
// cannot accept namespace empty nor label empty
|
||||
return false
|
||||
}
|
||||
if strings.LastIndex(label, "/") != p {
|
||||
// several slash in the Label
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue