aboutsummaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
authorGravatar Yong Tang <yong.tang.github@outlook.com> 2019-03-03 23:32:38 -0800
committerGravatar Miek Gieben <miek@miek.nl> 2019-03-04 07:32:38 +0000
commit9dd288943a778c19d5a798e1c1535cd0ba5d53c0 (patch)
tree2f555f01f74f41c005f75aa5a27659d6c5133410 /plugin
parentdfa413af096646e04882bb8312eef27fe1a160ef (diff)
downloadcoredns-9dd288943a778c19d5a798e1c1535cd0ba5d53c0.tar.gz
coredns-9dd288943a778c19d5a798e1c1535cd0ba5d53c0.tar.zst
coredns-9dd288943a778c19d5a798e1c1535cd0ba5d53c0.zip
Move *proxy* to external (#2651)
* Move *proxy* to external move the proxy plugin into coredns/proxy and remove it as a default plugin. Link the proxy to deprecated in plugin.cfg coredns/proxy doesn't compile because of the vendoring :( Signed-off-by: Miek Gieben <miek@miek.nl> * Add github.com/coredns/proxy Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Diffstat (limited to 'plugin')
-rw-r--r--plugin/cache/README.md5
-rw-r--r--plugin/etcd/README.md8
-rw-r--r--plugin/etcd/setup.go2
-rw-r--r--plugin/kubernetes/README.md23
-rw-r--r--plugin/loop/README.md12
-rw-r--r--plugin/proxy/OWNERS10
-rw-r--r--plugin/proxy/README.md160
-rw-r--r--plugin/proxy/dns.go100
-rw-r--r--plugin/proxy/dnstap.go56
-rw-r--r--plugin/proxy/dnstap_test.go57
-rw-r--r--plugin/proxy/down.go18
-rw-r--r--plugin/proxy/exchanger.go23
-rw-r--r--plugin/proxy/fuzz.go21
-rw-r--r--plugin/proxy/grpc.go99
-rw-r--r--plugin/proxy/grpc_test.go220
-rw-r--r--plugin/proxy/log_test.go5
-rw-r--r--plugin/proxy/metrics.go36
-rw-r--r--plugin/proxy/proxy.go183
-rw-r--r--plugin/proxy/proxy_test.go72
-rw-r--r--plugin/proxy/response.go21
-rw-r--r--plugin/proxy/setup.go53
-rw-r--r--plugin/proxy/upstream.go203
-rw-r--r--plugin/proxy/upstream_test.go327
-rw-r--r--plugin/template/README.md14
-rw-r--r--plugin/tls/README.md7
25 files changed, 36 insertions, 1699 deletions
diff --git a/plugin/cache/README.md b/plugin/cache/README.md
index 924a7543e..8b2bdf075 100644
--- a/plugin/cache/README.md
+++ b/plugin/cache/README.md
@@ -88,13 +88,14 @@ Proxy to Google Public DNS and only cache responses for example.org (or below).
~~~ corefile
. {
- proxy . 8.8.8.8:53
+ forward . 8.8.8.8:53
cache example.org
}
~~~
Enable caching for all zones, keep a positive cache size of 5000 and a negative cache size of 2500:
- ~~~ corefile
+
+~~~ corefile
. {
cache {
success 5000
diff --git a/plugin/etcd/README.md b/plugin/etcd/README.md
index 6ac267b51..393806a9f 100644
--- a/plugin/etcd/README.md
+++ b/plugin/etcd/README.md
@@ -10,7 +10,7 @@ The data in etcd instance has to be encoded as
a [message](https://github.com/skynetservices/skydns/blob/2fcff74cdc9f9a7dd64189a447ef27ac354b725f/msg/service.go#L26)
like [SkyDNS](https://github.com/skynetservices/skydns). It should also work just like SkyDNS.
-The etcd plugin makes extensive use of the proxy plugin to forward and query other servers in the
+The etcd plugin makes extensive use of the forward plugin to forward and query other servers in the
network.
## Syntax
@@ -46,7 +46,7 @@ etcd [ZONES...] {
* `credentials` is used to set the **USERNAME** and **PASSWORD** for accessing the etcd cluster.
* `upstream` upstream resolvers to be used resolve external names found in etcd (think CNAMEs)
pointing to external names. If you want CoreDNS to act as a proxy for clients, you'll need to add
- the proxy plugin. If no **ADDRESS** is given, CoreDNS will resolve CNAMEs against itself.
+ the *forward* plugin. If no **ADDRESS** is given, CoreDNS will resolve CNAMEs against itself.
**ADDRESS** can be an IP address, and IP:port or a string pointing to a file that is structured
as /etc/resolv.conf.
* `tls` followed by:
@@ -85,7 +85,7 @@ This is the default SkyDNS setup, with everything specified in full:
prometheus
cache 160 skydns.local
loadbalance
- proxy . 8.8.8.8:53 8.8.4.4:53
+ forward . 8.8.8.8:53 8.8.4.4:53
}
~~~
@@ -99,7 +99,7 @@ when resolving external pointing CNAMEs.
upstream
}
cache 160 skydns.local
- proxy . /etc/resolv.conf
+ forward . /etc/resolv.conf
}
~~~
diff --git a/plugin/etcd/setup.go b/plugin/etcd/setup.go
index d0cdbc705..3dfe6a49a 100644
--- a/plugin/etcd/setup.go
+++ b/plugin/etcd/setup.go
@@ -39,8 +39,6 @@ func setup(c *caddy.Controller) error {
func etcdParse(c *caddy.Controller) (*Etcd, error) {
etc := Etcd{
- // Don't default to a proxy for lookups.
- // Proxy: proxy.NewLookup([]string{"8.8.8.8:53", "8.8.4.4:53"}),
PathPrefix: "skydns",
Ctx: context.Background(),
}
diff --git a/plugin/kubernetes/README.md b/plugin/kubernetes/README.md
index 021b6553b..552050b0b 100644
--- a/plugin/kubernetes/README.md
+++ b/plugin/kubernetes/README.md
@@ -14,7 +14,7 @@ cluster. See the [deployment](https://github.com/coredns/deployment) repository
to deploy CoreDNS in Kubernetes](https://github.com/coredns/deployment/tree/master/kubernetes).
[stubDomains and upstreamNameservers](https://kubernetes.io/blog/2017/04/configuring-private-dns-zones-upstream-nameservers-kubernetes/)
-are implemented via the *proxy* plugin and kubernetes *upstream*. See example below.
+are implemented via the *forward* plugin and kubernetes *upstream*. See the examples below.
This plugin can only be used once per Server Block.
@@ -147,28 +147,33 @@ kubernetes cluster.local {
## stubDomains and upstreamNameservers
-Here we use the *proxy* plugin to implement a stubDomain that forwards `example.local` to the nameserver `10.100.0.10:53`.
+Here we use the *forward* plugin to implement a stubDomain that forwards `example.local` to the nameserver `10.100.0.10:53`.
The *upstream* option in the *kubernetes* plugin means that ExternalName services (CNAMEs) will be resolved using the respective proxy.
Also configured is an upstreamNameserver `8.8.8.8:53` that will be used for resolving names that do not fall in `cluster.local`
or `example.local`.
~~~ txt
-.:53 {
+cluster.local:53 {
kubernetes cluster.local {
upstream
}
- proxy example.local 10.100.0.10:53
- proxy . 8.8.8.8:53
+}
+example.local {
+ forward . 10.100.0.10:53
+}
+
+. {
+ forward . 8.8.8.8:53
}
~~~
The configuration above represents the following Kube-DNS stubDomains and upstreamNameservers configuration.
~~~ txt
- stubDomains: |
- {“example.local”: [“10.100.0.10:53”]}
- upstreamNameservers: |
- [“8.8.8.8:53”]
+stubDomains: |
+ {“example.local”: [“10.100.0.10:53”]}
+upstreamNameservers: |
+ [“8.8.8.8:53”]
~~~
## AutoPath
diff --git a/plugin/loop/README.md b/plugin/loop/README.md
index ee5029fd7..c893ed050 100644
--- a/plugin/loop/README.md
+++ b/plugin/loop/README.md
@@ -60,10 +60,10 @@ A forwarding loop is usually caused by:
* Most commonly, CoreDNS forwarding requests directly to itself. e.g. via a loopback address such as `127.0.0.1`, `::1` or `127.0.0.53`
* Less commonly, CoreDNS forwarding to an upstream server that in turn, forwards requests back to CoreDNS.
-To troubleshoot this problem, look in your Corefile for any `proxy` or `forward` to the zone
+To troubleshoot this problem, look in your Corefile for any `forward`s to the zone
in which the loop was detected. Make sure that they are not forwarding to a local address or
-to another DNS server that is forwarding requests back to CoreDNS. If `proxy` or `forward` are
- using a file (e.g. `/etc/resolv.conf`), make sure that file does not contain local addresses.
+to another DNS server that is forwarding requests back to CoreDNS. If `forward` is
+using a file (e.g. `/etc/resolv.conf`), make sure that file does not contain local addresses.
### Troubleshooting Loops In Kubernetes Clusters
@@ -75,7 +75,7 @@ on the host node (e.g. `systemd-resolved`). For example, in certain configurati
put the loopback address `127.0.0.53` as a nameserver into `/etc/resolv.conf`. Kubernetes (via `kubelet`) by default
will pass this `/etc/resolv.conf` file to all Pods using the `default` dnsPolicy rendering them
unable to make DNS lookups (this includes CoreDNS Pods). CoreDNS uses this `/etc/resolv.conf`
-as a list of upstreams to proxy/forward requests to. Since it contains a loopback address, CoreDNS ends up forwarding
+as a list of upstreams to forward requests to. Since it contains a loopback address, CoreDNS ends up forwarding
requests to itself.
There are many ways to work around this issue, some are listed here:
@@ -86,6 +86,6 @@ There are many ways to work around this issue, some are listed here:
`/run/systemd/resolve/resolv.conf` is typically the location of the "real" `resolv.conf`,
although this can be different depending on your distribution.
* Disable the local DNS cache on host nodes, and restore `/etc/resolv.conf` to the original.
-* A quick and dirty fix is to edit your Corefile, replacing `proxy . /etc/resolv.conf` with
-the ip address of your upstream DNS, for example `proxy . 8.8.8.8`. But this only fixes the issue for CoreDNS,
+* A quick and dirty fix is to edit your Corefile, replacing `forward . /etc/resolv.conf` with
+the ip address of your upstream DNS, for example `forward . 8.8.8.8`. But this only fixes the issue for CoreDNS,
kubelet will continue to forward the invalid `resolv.conf` to all `default` dnsPolicy Pods, leaving them unable to resolve DNS.
diff --git a/plugin/proxy/OWNERS b/plugin/proxy/OWNERS
deleted file mode 100644
index fb365f401..000000000
--- a/plugin/proxy/OWNERS
+++ /dev/null
@@ -1,10 +0,0 @@
-reviewers:
- - fturib
- - grobie
- - johnbelamaric
- - miekg
-approvers:
- - fturib
- - grobie
- - johnbelamaric
- - miekg
diff --git a/plugin/proxy/README.md b/plugin/proxy/README.md
deleted file mode 100644
index ead80548a..000000000
--- a/plugin/proxy/README.md
+++ /dev/null
@@ -1,160 +0,0 @@
-# proxy
-
-## Name
-
-*proxy* - facilitates both a basic reverse proxy and a robust load balancer.
-
-## Description
-
-The proxy has support for multiple backends. The load balancing features include multiple policies,
-health checks, and failovers. If all hosts fail their health check the proxy plugin will fail
-back to randomly selecting a target and sending packets to it.
-
-## Syntax
-
-In its most basic form, a simple reverse proxy uses this syntax:
-
-~~~
-proxy FROM TO
-~~~
-
-* **FROM** is the base domain to match for the request to be proxied.
-* **TO** is the destination endpoint to proxy to.
-
-However, advanced features including load balancing can be utilized with an expanded syntax:
-
-~~~
-proxy FROM TO... {
- policy random|least_conn|round_robin|sequential
- fail_timeout DURATION
- max_fails INTEGER
- health_check PATH:PORT [DURATION]
- except IGNORED_NAMES...
- spray
- protocol [dns [force_tcp]|grpc [insecure|CACERT|KEY CERT|KEY CERT CACERT]]
-}
-~~~
-
-* **FROM** is the name to match for the request to be proxied.
-* **TO** is the destination endpoint to proxy to. At least one is required, but multiple may be
- specified. **TO** may be an IP:Port pair, or may reference a file in resolv.conf format
-* `policy` is the load balancing policy to use; applies only with multiple backends. May be one of
- random, least_conn, round_robin or sequential. Default is random.
-* `fail_timeout` specifies how long to consider a backend as down after it has failed. While it is
- down, requests will not be routed to that backend. A backend is "down" if CoreDNS fails to
- communicate with it. The default value is 2 seconds ("2s").
-* `max_fails` is the number of failures within fail_timeout that are needed before considering
- a backend to be down. If 0, the backend will never be marked as down. Default is 1.
-* `health_check` will check **PATH** (on **PORT**) on each backend. If a backend returns a status code of
- 200-399, then that backend is marked healthy for double the healthcheck duration. If it doesn't,
- it is marked as unhealthy and no requests are routed to it. If this option is not provided then
- health checks are disabled. The default duration is 4 seconds ("4s").
-* **IGNORED_NAMES** in `except` is a space-separated list of domains to exclude from proxying.
- Requests that match none of these names will be passed through.
-* `spray` when all backends are unhealthy, randomly pick one to send the traffic to. (This is
- a failsafe.)
-* `protocol` specifies what protocol to use to speak to an upstream, `dns` (the default) is plain
- old DNS. The `grpc` option will talk to a server that has implemented
- the [DnsService](https://github.com/coredns/coredns/blob/master/pb/dns.proto).
-
-## Policies
-
-There are four load-balancing policies available:
-
-* `random` (default) - Randomly select a backend
-* `least_conn` - Select the backend with the fewest active connections
-* `round_robin` - Select the backend in round-robin fashion
-* `sequential` - Select the first available backend looking by order of declaration from left to right
-* `first` - Deprecated. Use sequential instead
-
-
-All polices implement randomly spraying packets to backend hosts when *no healthy* hosts are
-available. This is to preempt the case where the healthchecking (as a mechanism) fails.
-
-## Upstream Protocols
-
-`dns`
-: uses the standard DNS exchange. You can pass `force_tcp` to make sure that the proxied connection is performed
- over TCP, regardless of the inbound request's protocol.
-
-`grpc`
-: extra options are used to control how the TLS connection is made to the gRPC server.
-
- * None - No client authentication is used, and the system CAs are used to verify the server certificate.
- * `insecure` - TLS is not used, the connection is made in plaintext (not good in production).
- * **CACERT** - No client authentication is used, and the file **CACERT** is used to verify the server certificate.
- * **KEY** **CERT** - Client authentication is used with the specified key/cert pair. The server
- certificate is verified with the system CAs.
- * **KEY** **CERT** **CACERT** - Client authentication is used with the specified key/cert pair. The
- server certificate is verified using the **CACERT** file.
-
-## Metrics
-
-If monitoring is enabled (via the *prometheus* directive) then the following metric is exported:
-
-* `coredns_proxy_request_duration_seconds{server, proto, proto_proxy, family, to}` - duration per
- upstream interaction.
-* `coredns_proxy_request_count_total{server, proto, proto_proxy, family, to}` - query count per
- upstream.
-
-Where `proxy_proto` is the protocol used (`dns` or `grpc`) and `to` is **TO**
-specified in the config, `proto` is the protocol used by the incoming query ("tcp" or "udp"), family
-the transport family ("1" for IPv4, and "2" for IPv6). `Server` is the server responsible for the
-request (and metric). See the documentation in the metrics plugin.
-
-## Examples
-
-Proxy all requests within example.org. to a backend system:
-
-~~~
-proxy example.org 127.0.0.1:9005
-~~~
-
-Load-balance all requests between three backends (using random policy):
-
-~~~ corefile
-. {
- proxy . 10.0.0.10:53 10.0.0.11:1053 10.0.0.12
-}
-~~~
-
-Same as above, but round-robin style:
-
-~~~ corefile
-. {
- proxy . 10.0.0.10:53 10.0.0.11:1053 10.0.0.12 {
- policy round_robin
- }
-}
-~~~
-
-With health checks and proxy headers to pass hostname, IP, and scheme upstream:
-
-~~~ corefile
-. {
- proxy . 10.0.0.11:53 10.0.0.11:53 10.0.0.12:53 {
- policy round_robin
- health_check /health:8080
- }
-}
-~~~
-
-Proxy everything except requests to miek.nl or example.org
-
-~~~
-. {
- proxy . 10.0.0.10:1234 {
- except miek.nl example.org
- }
-}
-~~~
-
-Proxy everything except `example.org` using the host's `resolv.conf`'s nameservers:
-
-~~~ corefile
-. {
- proxy . /etc/resolv.conf {
- except example.org
- }
-}
-~~~
diff --git a/plugin/proxy/dns.go b/plugin/proxy/dns.go
deleted file mode 100644
index a96762c1d..000000000
--- a/plugin/proxy/dns.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package proxy
-
-import (
- "context"
- "net"
- "time"
-
- "github.com/coredns/coredns/request"
-
- "github.com/miekg/dns"
-)
-
-type dnsEx struct {
- Timeout time.Duration
- Options
-}
-
-// Options define the options understood by dns.Exchange.
-type Options struct {
- ForceTCP bool // If true use TCP for upstream no matter what
-}
-
-func newDNSEx() *dnsEx {
- return newDNSExWithOption(Options{})
-}
-
-func newDNSExWithOption(opt Options) *dnsEx {
- return &dnsEx{Timeout: defaultTimeout * time.Second, Options: opt}
-}
-
-func (d *dnsEx) Transport() string {
- if d.Options.ForceTCP {
- return "tcp"
- }
-
- // The protocol will be determined by `state.Proto()` during Exchange.
- return ""
-}
-func (d *dnsEx) Protocol() string { return "dns" }
-func (d *dnsEx) OnShutdown(p *Proxy) error { return nil }
-func (d *dnsEx) OnStartup(p *Proxy) error { return nil }
-
-// Exchange implements the Exchanger interface.
-func (d *dnsEx) Exchange(ctx context.Context, addr string, state request.Request) (*dns.Msg, error) {
- proto := state.Proto()
- if d.Options.ForceTCP {
- proto = "tcp"
- }
- co, err := net.DialTimeout(proto, addr, d.Timeout)
- if err != nil {
- return nil, err
- }
-
- reply, _, err := d.ExchangeConn(state.Req, co)
-
- co.Close()
-
- if reply != nil && reply.Truncated {
- // Suppress proxy error for truncated responses
- err = nil
- }
-
- if err != nil {
- return nil, err
- }
- reply.Id = state.Req.Id
-
- return reply, nil
-}
-
-func (d *dnsEx) ExchangeConn(m *dns.Msg, co net.Conn) (*dns.Msg, time.Duration, error) {
- start := time.Now()
- r, err := exchange(m, co)
- rtt := time.Since(start)
-
- return r, rtt, err
-}
-
-func exchange(m *dns.Msg, co net.Conn) (*dns.Msg, error) {
- opt := m.IsEdns0()
-
- udpsize := uint16(dns.MinMsgSize)
- // If EDNS0 is used use that for size.
- if opt != nil && opt.UDPSize() >= dns.MinMsgSize {
- udpsize = opt.UDPSize()
- }
-
- dnsco := &dns.Conn{Conn: co, UDPSize: udpsize}
-
- writeDeadline := time.Now().Add(defaultTimeout)
- dnsco.SetWriteDeadline(writeDeadline)
- if err := dnsco.WriteMsg(m); err != nil {
- log.Debugf("Failed to send message: %v", err)
- return nil, err
- }
-
- readDeadline := time.Now().Add(defaultTimeout)
- co.SetReadDeadline(readDeadline)
- return dnsco.ReadMsg()
-}
diff --git a/plugin/proxy/dnstap.go b/plugin/proxy/dnstap.go
deleted file mode 100644
index 4e5a8bd40..000000000
--- a/plugin/proxy/dnstap.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package proxy
-
-import (
- "context"
- "time"
-
- "github.com/coredns/coredns/plugin/dnstap"
- "github.com/coredns/coredns/plugin/dnstap/msg"
- "github.com/coredns/coredns/request"
-
- tap "github.com/dnstap/golang-dnstap"
- "github.com/miekg/dns"
-)
-
-func toDnstap(ctx context.Context, host string, ex Exchanger, state request.Request, reply *dns.Msg, start time.Time) error {
- tapper := dnstap.TapperFromContext(ctx)
- if tapper == nil {
- return nil
- }
-
- // Query
- b := msg.New().Time(start).HostPort(host)
-
- t := ex.Transport()
- if t == "" {
- t = state.Proto()
- }
- if t == "tcp" {
- b.SocketProto = tap.SocketProtocol_TCP
- } else {
- b.SocketProto = tap.SocketProtocol_UDP
- }
-
- if tapper.Pack() {
- b.Msg(state.Req)
- }
- m, err := b.ToOutsideQuery(tap.Message_FORWARDER_QUERY)
- if err != nil {
- return err
- }
- tapper.TapMessage(m)
-
- // Response
- if reply != nil {
- if tapper.Pack() {
- b.Msg(reply)
- }
- m, err := b.Time(time.Now()).ToOutsideResponse(tap.Message_FORWARDER_RESPONSE)
- if err != nil {
- return err
- }
- tapper.TapMessage(m)
- }
-
- return nil
-}
diff --git a/plugin/proxy/dnstap_test.go b/plugin/proxy/dnstap_test.go
deleted file mode 100644
index b07b081bc..000000000
--- a/plugin/proxy/dnstap_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package proxy
-
-import (
- "context"
- "testing"
- "time"
-
- "github.com/coredns/coredns/plugin/dnstap/msg"
- "github.com/coredns/coredns/plugin/dnstap/test"
- mwtest "github.com/coredns/coredns/plugin/test"
- "github.com/coredns/coredns/request"
-
- tap "github.com/dnstap/golang-dnstap"
- "github.com/miekg/dns"
-)
-
-func testCase(t *testing.T, ex Exchanger, q, r *dns.Msg, datq, datr *msg.Builder) {
- tapq, _ := datq.ToOutsideQuery(tap.Message_FORWARDER_QUERY)
- tapr, _ := datr.ToOutsideResponse(tap.Message_FORWARDER_RESPONSE)
- ctx := test.Context{}
- err := toDnstap(&ctx, "10.240.0.1:40212", ex,
- request.Request{W: &mwtest.ResponseWriter{}, Req: q}, r, time.Now())
- if err != nil {
- t.Fatal(err)
- }
- if len(ctx.Trap) != 2 {
- t.Fatalf("Messages: %d", len(ctx.Trap))
- }
- if !test.MsgEqual(ctx.Trap[0], tapq) {
- t.Errorf("Want: %v\nhave: %v", tapq, ctx.Trap[0])
- }
- if !test.MsgEqual(ctx.Trap[1], tapr) {
- t.Errorf("Want: %v\nhave: %v", tapr, ctx.Trap[1])
- }
-}
-
-func TestDnstap(t *testing.T) {
- q := mwtest.Case{Qname: "example.org", Qtype: dns.TypeA}.Msg()
- r := mwtest.Case{
- Qname: "example.org.", Qtype: dns.TypeA,
- Answer: []dns.RR{
- mwtest.A("example.org. 3600 IN A 10.0.0.1"),
- },
- }.Msg()
- tapq, tapr := test.TestingData(), test.TestingData()
- testCase(t, newDNSEx(), q, r, tapq, tapr)
- tapq.SocketProto = tap.SocketProtocol_TCP
- tapr.SocketProto = tap.SocketProtocol_TCP
- testCase(t, newDNSExWithOption(Options{ForceTCP: true}), q, r, tapq, tapr)
-}
-
-func TestNoDnstap(t *testing.T) {
- err := toDnstap(context.TODO(), "", nil, request.Request{}, nil, time.Now())
- if err != nil {
- t.Fatal(err)
- }
-}
diff --git a/plugin/proxy/down.go b/plugin/proxy/down.go
deleted file mode 100644
index 11f839b46..000000000
--- a/plugin/proxy/down.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package proxy
-
-import (
- "sync/atomic"
-
- "github.com/coredns/coredns/plugin/pkg/healthcheck"
-)
-
-// Default CheckDown functions for use in the proxy plugin.
-var checkDownFunc = func(upstream *staticUpstream) healthcheck.UpstreamHostDownFunc {
- return func(uh *healthcheck.UpstreamHost) bool {
- fails := atomic.LoadInt32(&uh.Fails)
- if fails >= upstream.MaxFails && upstream.MaxFails != 0 {
- return true
- }
- return false
- }
-}
diff --git a/plugin/proxy/exchanger.go b/plugin/proxy/exchanger.go
deleted file mode 100644
index e96dac5a4..000000000
--- a/plugin/proxy/exchanger.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package proxy
-
-import (
- "context"
-
- "github.com/coredns/coredns/request"
-
- "github.com/miekg/dns"
-)
-
-// Exchanger is an interface that specifies a type implementing a DNS resolver that
-// can use whatever transport it likes.
-type Exchanger interface {
- Exchange(ctx context.Context, addr string, state request.Request) (*dns.Msg, error)
- Protocol() string
-
- // Transport returns the only transport protocol used by this Exchanger or "".
- // If the return value is "", Exchange must use `state.Proto()`.
- Transport() string
-
- OnStartup(*Proxy) error
- OnShutdown(*Proxy) error
-}
diff --git a/plugin/proxy/fuzz.go b/plugin/proxy/fuzz.go
deleted file mode 100644
index bb8e07f8a..000000000
--- a/plugin/proxy/fuzz.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// +build fuzz
-
-package proxy
-
-import (
- "github.com/coredns/coredns/plugin/pkg/fuzz"
-
- "github.com/mholt/caddy"
-)
-
-// Fuzz fuzzes proxy.
-func Fuzz(data []byte) int {
- c := caddy.NewTestController("dns", "proxy . 8.8.8.8:53")
- up, err := NewStaticUpstreams(&c.Dispenser)
- if err != nil {
- return 0
- }
- p := &Proxy{Upstreams: &up}
-
- return fuzz.Do(p, data)
-}
diff --git a/plugin/proxy/grpc.go b/plugin/proxy/grpc.go
deleted file mode 100644
index dc388c91e..000000000
--- a/plugin/proxy/grpc.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package proxy
-
-import (
- "context"
- "crypto/tls"
- "fmt"
-
- "github.com/coredns/coredns/pb"
- "github.com/coredns/coredns/plugin/pkg/trace"
- "github.com/coredns/coredns/request"
-
- "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
- "github.com/miekg/dns"
- opentracing "github.com/opentracing/opentracing-go"
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials"
-)
-
-type grpcClient struct {
- dialOpts []grpc.DialOption
- clients map[string]pb.DnsServiceClient
- conns []*grpc.ClientConn
- upstream *staticUpstream
-}
-
-func newGrpcClient(tls *tls.Config, u *staticUpstream) *grpcClient {
- g := &grpcClient{upstream: u}
-
- if tls == nil {
- g.dialOpts = append(g.dialOpts, grpc.WithInsecure())
- } else {
- g.dialOpts = append(g.dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(tls)))
- }
- g.clients = map[string]pb.DnsServiceClient{}
-
- return g
-}
-
-func (g *grpcClient) Exchange(ctx context.Context, addr string, state request.Request) (*dns.Msg, error) {
- msg, err := state.Req.Pack()
- if err != nil {
- return nil, err
- }
-
- if cl, ok := g.clients[addr]; ok {
- reply, err := cl.Query(ctx, &pb.DnsPacket{Msg: msg})
- if err != nil {
- return nil, err
- }
- d := new(dns.Msg)
- err = d.Unpack(reply.Msg)
- if err != nil {
- return nil, err
- }
- return d, nil
- }
- return nil, fmt.Errorf("grpc exchange - no connection available for host: %s ", addr)
-}
-
-func (g *grpcClient) Transport() string { return "tcp" }
-
-func (g *grpcClient) Protocol() string { return "grpc" }
-
-func (g *grpcClient) OnShutdown(p *Proxy) error {
- g.clients = map[string]pb.DnsServiceClient{}
- for i, conn := range g.conns {
- err := conn.Close()
- if err != nil {
- log.Warningf("Error closing connection %d: %s\n", i, err)
- }
- }
- g.conns = []*grpc.ClientConn{}
- return nil
-}
-
-func (g *grpcClient) OnStartup(p *Proxy) error {
- dialOpts := g.dialOpts
- if p.Trace != nil {
- if t, ok := p.Trace.(trace.Trace); ok {
- onlyIfParent := func(parentSpanCtx opentracing.SpanContext, method string, req, resp interface{}) bool {
- return parentSpanCtx != nil
- }
- intercept := otgrpc.OpenTracingClientInterceptor(t.Tracer(), otgrpc.IncludingSpans(onlyIfParent))
- dialOpts = append(dialOpts, grpc.WithUnaryInterceptor(intercept))
- } else {
- log.Warningf("Wrong type for trace plugin reference: %s", p.Trace)
- }
- }
- for _, host := range g.upstream.Hosts {
- conn, err := grpc.Dial(host.Name, dialOpts...)
- if err != nil {
- log.Warningf("Skipping gRPC host '%s' due to Dial error: %s\n", host.Name, err)
- } else {
- g.clients[host.Name] = pb.NewDnsServiceClient(conn)
- g.conns = append(g.conns, conn)
- }
- }
- return nil
-}
diff --git a/plugin/proxy/grpc_test.go b/plugin/proxy/grpc_test.go
deleted file mode 100644
index ec54375d3..000000000
--- a/plugin/proxy/grpc_test.go
+++ /dev/null
@@ -1,220 +0,0 @@
-package proxy
-
-import (
- "context"
- "fmt"
- "testing"
-
- "github.com/coredns/coredns/plugin/pkg/healthcheck"
- "github.com/coredns/coredns/plugin/pkg/tls"
- "github.com/coredns/coredns/plugin/test"
- "github.com/coredns/coredns/request"
-
- "github.com/miekg/dns"
- "google.golang.org/grpc/grpclog"
-)
-
-func init() {
- grpclog.SetLoggerV2(discardV2{})
-}
-
-func buildPool(size int) ([]*healthcheck.UpstreamHost, func(), error) {
- ups := make([]*healthcheck.UpstreamHost, size)
- srvs := []*dns.Server{}
- errs := []error{}
- for i := 0; i < size; i++ {
- srv, addr, err := test.TCPServer("localhost:0")
- if err != nil {
- errs = append(errs, err)
- continue
- }
- ups[i] = &healthcheck.UpstreamHost{Name: addr}
- srvs = append(srvs, srv)
- }
- stopIt := func() {
- for _, s := range srvs {
- s.Shutdown()
- }
- }
- if len(errs) > 0 {
- go stopIt()
- valErr := ""
- for _, e := range errs {
- valErr += fmt.Sprintf("%v\n", e)
- }
- return nil, nil, fmt.Errorf("error at allocation of the pool : %v", valErr)
- }
- return ups, stopIt, nil
-}
-
-func TestGRPCStartupShutdown(t *testing.T) {
-
- pool, closePool, err := buildPool(2)
- if err != nil {
- t.Fatalf("Error creating the pool of upstream for the test : %s", err)
- }
- defer closePool()
-
- upstream := &staticUpstream{
- from: ".",
- HealthCheck: healthcheck.HealthCheck{
- Hosts: pool,
- },
- }
- g := newGrpcClient(nil, upstream)
- upstream.ex = g
-
- p := &Proxy{}
- p.Upstreams = &[]Upstream{upstream}
-
- err = g.OnStartup(p)
- if err != nil {
- t.Fatalf("Error starting grpc client exchanger: %s", err)
- }
- if len(g.clients) != len(pool) {
- t.Fatalf("Expected %d grpc clients but found %d", len(pool), len(g.clients))
- }
-
- err = g.OnShutdown(p)
- if err != nil {
- t.Fatalf("Error stopping grpc client exchanger: %s", err)
- }
- if len(g.clients) != 0 {
- t.Errorf("Shutdown didn't remove clients, found %d", len(g.clients))
- }
- if len(g.conns) != 0 {
- t.Errorf("Shutdown didn't remove conns, found %d", len(g.conns))
- }
-}
-
-func TestGRPCRunAQuery(t *testing.T) {
-
- pool, closePool, err := buildPool(2)
- if err != nil {
- t.Fatalf("Error creating the pool of upstream for the test : %s", err)
- }
- defer closePool()
-
- upstream := &staticUpstream{
- from: ".",
- HealthCheck: healthcheck.HealthCheck{
- Hosts: pool,
- },
- }
- g := newGrpcClient(nil, upstream)
- upstream.ex = g
-
- p := &Proxy{}
- p.Upstreams = &[]Upstream{upstream}
-
- err = g.OnStartup(p)
- if err != nil {
- t.Fatalf("Error starting grpc client exchanger: %s", err)
- }
- // verify the client is usable, or an error is properly raised
- state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)}
- g.Exchange(context.TODO(), "localhost:10053", state)
-
- // verify that you have proper error if the hostname is unknwn or not registered
- _, err = g.Exchange(context.TODO(), "invalid:10055", state)
- if err == nil {
- t.Errorf("Expecting a proper error when querying gRPC client with invalid hostname : %s", err)
- }
-
- err = g.OnShutdown(p)
- if err != nil {
- t.Fatalf("Error stopping grpc client exchanger: %s", err)
- }
-}
-
-func TestGRPCRunAQueryOnSecureLinkWithInvalidCert(t *testing.T) {
-
- pool, closePool, err := buildPool(1)
- if err != nil {
- t.Fatalf("Error creating the pool of upstream for the test : %s", err)
- }
- defer closePool()
-
- upstream := &staticUpstream{
- from: ".",
- HealthCheck: healthcheck.HealthCheck{
- Hosts: pool,
- },
- }
-
- filename, rmFunc, err := test.TempFile("", aCert)
- if err != nil {
- t.Errorf("Error saving file : %s", err)
- return
- }
- defer rmFunc()
-
- tls, _ := tls.NewTLSClientConfig(filename)
- // ignore error as the certificate is known valid
-
- g := newGrpcClient(tls, upstream)
- upstream.ex = g
-
- p := &Proxy{}
- p.Upstreams = &[]Upstream{upstream}
-
- // Although dial will not work, it is not expected to have an error
- err = g.OnStartup(p)
- if err != nil {
- t.Fatalf("Error starting grpc client exchanger: %s", err)
- }
-
- // verify that you have proper error if the hostname is unknwn or not registered
- state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)}
- _, err = g.Exchange(context.TODO(), pool[0].Name+"-whatever", state)
- if err == nil {
- t.Errorf("Error in Exchange process : %s ", err)
- }
-
- err = g.OnShutdown(p)
- if err != nil {
- t.Fatalf("Error stopping grpc client exchanger: %s", err)
- }
-}
-
-// discard is a Logger that outputs nothing.
-type discardV2 struct{}
-
-func (d discardV2) Info(args ...interface{}) {}
-func (d discardV2) Infoln(args ...interface{}) {}
-func (d discardV2) Infof(format string, args ...interface{}) {}
-func (d discardV2) Warning(args ...interface{}) {}
-func (d discardV2) Warningln(args ...interface{}) {}
-func (d discardV2) Warningf(format string, args ...interface{}) {}
-func (d discardV2) Error(args ...interface{}) {}
-func (d discardV2) Errorln(args ...interface{}) {}
-func (d discardV2) Errorf(format string, args ...interface{}) {}
-func (d discardV2) Fatal(args ...interface{}) {}
-func (d discardV2) Fatalln(args ...interface{}) {}
-func (d discardV2) Fatalf(format string, args ...interface{}) {}
-func (d discardV2) V(l int) bool { return true }
-
-const (
- aCert = `-----BEGIN CERTIFICATE-----
- MIIDlDCCAnygAwIBAgIJAPaRnBJUE/FVMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQwHhcNMTcxMTI0MTM0OTQ3WhcNMTgxMTI0MTM0OTQ3WjBF
-MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
-ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAuTDeAoWS6tdZVcp/Vh3FlagbC+9Ohi5VjRXgkpcn9JopbcF5s2jpl1v+
-cRpqkrmNNKLh8qOhmgdZQdh185VNe/iZ94H42qwKZ48vvnC5hLkk3MdgUT2ewgup
-vZhy/Bb1bX+buCWkQa1u8SIilECMIPZHhBP4TuBUKJWK8bBEFAeUnxB5SCkX+un4
-pctRlcfg8sX/ghADnp4e//YYDqex+1wQdFqM5zWhWDZAzc5Kdkyy9r+xXNfo4s1h
-fI08f6F4skz1koxG2RXOzQ7OK4YxFwT2J6V72iyzUIlRGZTbYDvair/zm1kjTF1R
-B1B+XLJF9oIB4BMZbekf033ZVaQ8YwIDAQABo4GGMIGDMDMGA1UdEQQsMCqHBH8A
-AAGHBDR3AQGHBDR3AQCHBDR3KmSHBDR3KGSHBDR3KmWHBDR3KtIwHQYDVR0OBBYE
-FFAEccLm7D/rN3fEe1fwzH7p0spAMB8GA1UdIwQYMBaAFFAEccLm7D/rN3fEe1fw
-zH7p0spAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAF4zqaucNcK2
-GwYfijwbbtgMqPEvbReUEXsC65riAPjksJQ9L2YxQ7K0RIugRizuD1DNQam+FSb0
-cZEMEKzvMUIexbhZNFINWXY2X9yUS/oZd5pWP0WYIhn6qhmLvzl9XpxNPVzBXYWe
-duMECCigU2x5tAGmFa6g/pXXOoZCBRzFXwXiuNhSyhJEEwODjLZ6vgbySuU2jso3
-va4FKFDdVM16s1/RYOK5oM48XytCMB/JoYoSJHPfpt8LpVNAQEHMvPvHwuZBON/z
-q8HFtDjT4pBpB8AfuzwtUZ/zJ5atwxa5+ahcqRnK2kX2RSINfyEy43FZjLlvjcGa
-UIRTUJK1JKg=
------END CERTIFICATE-----`
-)
diff --git a/plugin/proxy/log_test.go b/plugin/proxy/log_test.go
deleted file mode 100644
index e0c50773b..000000000
--- a/plugin/proxy/log_test.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package proxy
-
-import clog "github.com/coredns/coredns/plugin/pkg/log"
-
-func init() { clog.Discard() }
diff --git a/plugin/proxy/metrics.go b/plugin/proxy/metrics.go
deleted file mode 100644
index 0bea5ae4b..000000000
--- a/plugin/proxy/metrics.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package proxy
-
-import (
- "github.com/coredns/coredns/plugin"
-
- "github.com/prometheus/client_golang/prometheus"
-)
-
-// Metrics the proxy plugin exports.
-var (
- RequestCount = prometheus.NewCounterVec(prometheus.CounterOpts{
- Namespace: plugin.Namespace,
- Subsystem: "proxy",
- Name: "request_count_total",
- Help: "Counter of requests made per protocol, proxy protocol, family and upstream.",
- }, []string{"server", "proto", "proxy_proto", "family", "to"})
- RequestDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
- Namespace: plugin.Namespace,
- Subsystem: "proxy",
- Name: "request_duration_seconds",
- Buckets: plugin.TimeBuckets,
- Help: "Histogram of the time (in seconds) each request took.",
- }, []string{"server", "proto", "proxy_proto", "family", "to"})
-)
-
-// familyToString returns the string form of either 1, or 2. Returns
-// empty string is not a known family
-func familyToString(f int) string {
- if f == 1 {
- return "1"
- }
- if f == 2 {
- return "2"
- }
- return ""
-}
diff --git a/plugin/proxy/proxy.go b/plugin/proxy/proxy.go
deleted file mode 100644
index ad333fbd1..000000000
--- a/plugin/proxy/proxy.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// Package proxy is plugin that proxies requests.
-package proxy
-
-import (
- "context"
- "errors"
- "fmt"
- "net"
- "sync/atomic"
- "time"
-
- "github.com/coredns/coredns/plugin"
- "github.com/coredns/coredns/plugin/metrics"
- "github.com/coredns/coredns/plugin/pkg/healthcheck"
- "github.com/coredns/coredns/request"
-
- "github.com/miekg/dns"
- ot "github.com/opentracing/opentracing-go"
-)
-
-var (
- errUnreachable = errors.New("unreachable backend")
- errInvalidProtocol = errors.New("invalid protocol")
- errInvalidDomain = errors.New("invalid path for proxy")
-)
-
-// Proxy represents a plugin instance that can proxy requests to another (DNS) server.
-type Proxy struct {
- Next plugin.Handler
-
- // Upstreams is a pointer to a slice, so we can update the upstream (used for Google)
- // midway.
-
- Upstreams *[]Upstream
-
- // Trace is the Trace plugin, if it is installed
- // This is used by the grpc exchanger to trace through the grpc calls
- Trace plugin.Handler
-}
-
-// Upstream manages a pool of proxy upstream hosts. Select should return a
-// suitable upstream host, or nil if no such hosts are available.
-type Upstream interface {
- // The domain name this upstream host should be routed on.
- From() string
- // Selects an upstream host to be routed to.
- Select() *healthcheck.UpstreamHost
- // Checks if subdomain is not an ignored.
- IsAllowedDomain(string) bool
- // Exchanger returns the exchanger to be used for this upstream.
- Exchanger() Exchanger
- // Stops the upstream from proxying requests to shutdown goroutines cleanly.
- Stop() error
-}
-
-// tryDuration is how long to try upstream hosts; failures result in
-// immediate retries until this duration ends or we get a nil host.
-var tryDuration = 16 * time.Second
-
-// ServeDNS satisfies the plugin.Handler interface.
-func (p Proxy) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
- var span, child ot.Span
- span = ot.SpanFromContext(ctx)
- state := request.Request{W: w, Req: r}
-
- upstream := p.match(state)
- if upstream == nil {
- return plugin.NextOrFailure(p.Name(), p.Next, ctx, w, r)
- }
-
- for {
- start := time.Now()
- var reply *dns.Msg
- var backendErr error
-
- // Since Select() should give us "up" hosts, keep retrying
- // hosts until timeout (or until we get a nil host).
- for time.Since(start) < tryDuration {
- host := upstream.Select()
- if host == nil {
- return dns.RcodeServerFailure, fmt.Errorf("%s: %s", errUnreachable, "no upstream host")
- }
-
- if span != nil {
- child = span.Tracer().StartSpan("exchange", ot.ChildOf(span.Context()))
- ctx = ot.ContextWithSpan(ctx, child)
- }
-
- atomic.AddInt64(&host.Conns, 1)
-
- RequestCount.WithLabelValues(metrics.WithServer(ctx), state.Proto(), upstream.Exchanger().Protocol(), familyToString(state.Family()), host.Name).Add(1)
-
- reply, backendErr = upstream.Exchanger().Exchange(ctx, host.Name, state)
-
- atomic.AddInt64(&host.Conns, -1)
-
- if child != nil {
- child.Finish()
- }
-
- taperr := toDnstap(ctx, host.Name, upstream.Exchanger(), state, reply, start)
-
- if backendErr == nil {
-
- // Check if the reply is correct; if not return FormErr.
- if !state.Match(reply) {
- formerr := state.ErrorMessage(dns.RcodeFormatError)
- w.WriteMsg(formerr)
- return 0, taperr
- }
-
- w.WriteMsg(reply)
-
- RequestDuration.WithLabelValues(metrics.WithServer(ctx), state.Proto(), upstream.Exchanger().Protocol(), familyToString(state.Family()), host.Name).Observe(time.Since(start).Seconds())
-
- return 0, taperr
- }
-
- // A "ANY isc.org" query is being dropped by ISC's nameserver, we see this as a i/o timeout, but
- // would then mark our upstream is being broken. We should not do this if we consider the error temporary.
- // Of course it could really be that our upstream is broken
- if oe, ok := backendErr.(*net.OpError); ok {
- // Note this keeps looping and trying until tryDuration is hit, at which point our client
- // might be long gone...
- if oe.Timeout() {
- // Our upstream's upstream is probably messing up, continue with next selected
- // host - which my be the *same* one as we don't set any uh.Fails.
- continue
- }
- }
-
- timeout := host.FailTimeout
- if timeout == 0 {
- timeout = defaultFailTimeout
- }
-
- atomic.AddInt32(&host.Fails, 1)
- fails := atomic.LoadInt32(&host.Fails)
-
- go func(host *healthcheck.UpstreamHost, timeout time.Duration) {
- time.Sleep(timeout)
- // we may go negative here, should be rectified by the HC.
- atomic.AddInt32(&host.Fails, -1)
- if fails%failureCheck == 0 { // Kick off healthcheck on every third failure.
- host.HealthCheckURL()
- }
- }(host, timeout)
- }
-
- return dns.RcodeServerFailure, fmt.Errorf("%s: %s", errUnreachable, backendErr)
- }
-}
-
-func (p Proxy) match(state request.Request) (u Upstream) {
- if p.Upstreams == nil {
- return nil
- }
-
- longestMatch := 0
- for _, upstream := range *p.Upstreams {
- from := upstream.From()
-
- if !plugin.Name(from).Matches(state.Name()) || !upstream.IsAllowedDomain(state.Name()) {
- continue
- }
-
- if lf := len(from); lf > longestMatch {
- longestMatch = lf
- u = upstream
- }
- }
- return u
-
-}
-
-// Name implements the Handler interface.
-func (p Proxy) Name() string { return "proxy" }
-
-const (
- defaultFailTimeout = 2 * time.Second
- defaultTimeout = 5 * time.Second
- failureCheck = 3
-)
diff --git a/plugin/proxy/proxy_test.go b/plugin/proxy/proxy_test.go
deleted file mode 100644
index 0d29c2329..000000000
--- a/plugin/proxy/proxy_test.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package proxy
-
-import (
- "fmt"
- "net/http"
- "net/http/httptest"
- "strings"
- "sync/atomic"
- "testing"
- "time"
-
- "github.com/mholt/caddy/caddyfile"
-)
-
-func TestStop(t *testing.T) {
- config := "proxy . %s {\n health_check /healthcheck:%s %dms \n}"
- tests := []struct {
- intervalInMilliseconds int
- numHealthcheckIntervals int
- }{
- {5, 1},
- {5, 2},
- {5, 3},
- }
-
- for i, test := range tests {
- t.Run(fmt.Sprintf("Test %d", i), func(t *testing.T) {
-
- // Set up proxy.
- var counter int64
- backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- r.Body.Close()
- atomic.AddInt64(&counter, 1)
- }))
-
- defer backend.Close()
-
- port := backend.URL[17:] // Remove all crap up to the port
- back := backend.URL[7:] // Remove http://
- c := caddyfile.NewDispenser("Testfile", strings.NewReader(fmt.Sprintf(config, back, port, test.intervalInMilliseconds)))
- upstreams, err := NewStaticUpstreams(&c)
- if err != nil {
- t.Errorf("Test %d, expected no error. Got: %s", i, err)
- }
-
- // Give some time for healthchecks to hit the server.
- time.Sleep(time.Duration(test.intervalInMilliseconds*test.numHealthcheckIntervals) * time.Millisecond)
-
- for _, upstream := range upstreams {
- if err := upstream.Stop(); err != nil {
- t.Errorf("Test %d, expected no error stopping upstream, got: %s", i, err)
- }
- }
-
- counterAfterShutdown := atomic.LoadInt64(&counter)
-
- // Give some time to see if healthchecks are still hitting the server.
- time.Sleep(time.Duration(test.intervalInMilliseconds*test.numHealthcheckIntervals) * time.Millisecond)
-
- if counterAfterShutdown == 0 {
- t.Errorf("Test %d, Expected healthchecks to hit test server, got none", i)
- }
-
- // health checks are in a go routine now, so one may well occur after we shutdown,
- // but we only ever expect one more
- counterAfterWaiting := atomic.LoadInt64(&counter)
- if counterAfterWaiting > (counterAfterShutdown + 1) {
- t.Errorf("Test %d, expected no more healthchecks after shutdown. got: %d healthchecks after shutdown", i, counterAfterWaiting-counterAfterShutdown)
- }
- })
- }
-}
diff --git a/plugin/proxy/response.go b/plugin/proxy/response.go
deleted file mode 100644
index 2ad553c41..000000000
--- a/plugin/proxy/response.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package proxy
-
-import (
- "net"
-
- "github.com/miekg/dns"
-)
-
-type fakeBootWriter struct {
- dns.ResponseWriter
-}
-
-func (w *fakeBootWriter) LocalAddr() net.Addr {
- local := net.ParseIP("127.0.0.1")
- return &net.UDPAddr{IP: local, Port: 53} // Port is not used here
-}
-
-func (w *fakeBootWriter) RemoteAddr() net.Addr {
- remote := net.ParseIP("8.8.8.8")
- return &net.UDPAddr{IP: remote, Port: 53} // Port is not used here
-}
diff --git a/plugin/proxy/setup.go b/plugin/proxy/setup.go
deleted file mode 100644
index 2f3d7dd62..000000000
--- a/plugin/proxy/setup.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package proxy
-
-import (
- "github.com/coredns/coredns/core/dnsserver"
- "github.com/coredns/coredns/plugin"
- "github.com/coredns/coredns/plugin/metrics"
- clog "github.com/coredns/coredns/plugin/pkg/log"
-
- "github.com/mholt/caddy"
-)
-
-var log = clog.NewWithPlugin("proxy")
-
-func init() {
- caddy.RegisterPlugin("proxy", caddy.Plugin{
- ServerType: "dns",
- Action: setup,
- })
-}
-
-func setup(c *caddy.Controller) error {
- upstreams, err := NewStaticUpstreams(&c.Dispenser)
- if err != nil {
- return plugin.Error("proxy", err)
- }
-
- t := dnsserver.GetConfig(c).Handler("trace")
- P := &Proxy{Trace: t}
- dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
- P.Next = next
- P.Upstreams = &upstreams
- return P
- })
-
- c.OnStartup(func() error {
- metrics.MustRegister(c, RequestCount, RequestDuration)
- return nil
- })
-
- for i := range upstreams {
- u := upstreams[i]
- c.OnStartup(func() error {
- return u.Exchanger().OnStartup(P)
- })
- c.OnShutdown(func() error {
- return u.Exchanger().OnShutdown(P)
- })
- // Register shutdown handlers.
- c.OnShutdown(u.Stop)
- }
-
- return nil
-}
diff --git a/plugin/proxy/upstream.go b/plugin/proxy/upstream.go
deleted file mode 100644
index 0d62f45e2..000000000
--- a/plugin/proxy/upstream.go
+++ /dev/null
@@ -1,203 +0,0 @@
-package proxy
-
-import (
- "fmt"
- "net"
- "strconv"
- "time"
-
- "github.com/coredns/coredns/plugin"
- "github.com/coredns/coredns/plugin/pkg/healthcheck"
- "github.com/coredns/coredns/plugin/pkg/parse"
- "github.com/coredns/coredns/plugin/pkg/tls"
- "github.com/mholt/caddy/caddyfile"
- "github.com/miekg/dns"
-)
-
-type staticUpstream struct {
- from string
-
- healthcheck.HealthCheck
-
- IgnoredSubDomains []string
- ex Exchanger
-}
-
-// NewStaticUpstreams parses the configuration input and sets up
-// static upstreams for the proxy plugin.
-func NewStaticUpstreams(c *caddyfile.Dispenser) ([]Upstream, error) {
- var upstreams []Upstream
- for c.Next() {
- u, err := NewStaticUpstream(c)
- if err != nil {
- return upstreams, err
- }
- upstreams = append(upstreams, u)
- }
- return upstreams, nil
-}
-
-// NewStaticUpstream parses the configuration of a single upstream
-// starting from the FROM
-func NewStaticUpstream(c *caddyfile.Dispenser) (Upstream, error) {
- upstream := &staticUpstream{
- from: ".",
- HealthCheck: healthcheck.HealthCheck{
- FailTimeout: 5 * time.Second,
- MaxFails: 3,
- },
- ex: newDNSEx(),
- }
-
- if !c.Args(&upstream.from) {
- return upstream, c.ArgErr()
- }
- upstream.from = plugin.Host(upstream.from).Normalize()
-
- to := c.RemainingArgs()
- if len(to) == 0 {
- return upstream, c.ArgErr()
- }
-
- // process the host list, substituting in any nameservers in files
- toHosts, err := parse.HostPortOrFile(to...)
- if err != nil {
- return upstream, err
- }
-
- if len(toHosts) > max {
- return upstream, fmt.Errorf("more than %d TOs configured: %d", max, len(toHosts))
- }
-
- for c.NextBlock() {
- if err := parseBlock(c, upstream); err != nil {
- return upstream, err
- }
- }
-
- upstream.Hosts = make([]*healthcheck.UpstreamHost, len(toHosts))
-
- for i, host := range toHosts {
- uh := &healthcheck.UpstreamHost{
- Name: host,
- FailTimeout: upstream.FailTimeout,
- CheckDown: checkDownFunc(upstream),
- }
- upstream.Hosts[i] = uh
- }
- upstream.Start()
-
- return upstream, nil
-}
-
-func parseBlock(c *caddyfile.Dispenser, u *staticUpstream) error {
- switch c.Val() {
- case "policy":
- if !c.NextArg() {
- return c.ArgErr()
- }
- policyCreateFunc, ok := healthcheck.SupportedPolicies[c.Val()]
- if !ok {
- return c.ArgErr()
- }
- u.Policy = policyCreateFunc()
- case "fail_timeout":
- if !c.NextArg() {
- return c.ArgErr()
- }
- dur, err := time.ParseDuration(c.Val())
- if err != nil {
- return err
- }
- u.FailTimeout = dur
- case "max_fails":
- if !c.NextArg() {
- return c.ArgErr()
- }
- n, err := strconv.Atoi(c.Val())
- if err != nil {
- return err
- }
- u.MaxFails = int32(n)
- case "health_check":
- if !c.NextArg() {
- return c.ArgErr()
- }
- var err error
- u.HealthCheck.Path, u.HealthCheck.Port, err = net.SplitHostPort(c.Val())
- if err != nil {
- return err
- }
- u.HealthCheck.Interval = 4 * time.Second
- if c.NextArg() {
- dur, err := time.ParseDuration(c.Val())
- if err != nil {
- return err
- }
- u.HealthCheck.Interval = dur
- }
- case "except":
- ignoredDomains := c.RemainingArgs()
- if len(ignoredDomains) == 0 {
- return c.ArgErr()
- }
- for i := 0; i < len(ignoredDomains); i++ {
- ignoredDomains[i] = plugin.Host(ignoredDomains[i]).Normalize()
- }
- u.IgnoredSubDomains = ignoredDomains
- case "spray":
- u.Spray = &healthcheck.Spray{}
- case "protocol":
- encArgs := c.RemainingArgs()
- if len(encArgs) == 0 {
- return c.ArgErr()
- }
- switch encArgs[0] {
- case "dns":
- if len(encArgs) > 1 {
- if encArgs[1] == "force_tcp" {
- opts := Options{ForceTCP: true}
- u.ex = newDNSExWithOption(opts)
- } else {
- return fmt.Errorf("only force_tcp allowed as parameter to dns")
- }
- } else {
- u.ex = newDNSEx()
- }
- case "grpc":
- if len(encArgs) == 2 && encArgs[1] == "insecure" {
- u.ex = newGrpcClient(nil, u)
- return nil
- }
- tls, err := tls.NewTLSConfigFromArgs(encArgs[1:]...)
- if err != nil {
- return err
- }
- u.ex = newGrpcClient(tls, u)
- default:
- return fmt.Errorf("%s: %s", errInvalidProtocol, encArgs[0])
- }
-
- default:
- return c.Errf("unknown property '%s'", c.Val())
- }
- return nil
-}
-
-func (u *staticUpstream) IsAllowedDomain(name string) bool {
- if dns.Name(name) == dns.Name(u.From()) {
- return true
- }
-
- for _, ignoredSubDomain := range u.IgnoredSubDomains {
- if plugin.Name(ignoredSubDomain).Matches(name) {
- return false
- }
- }
- return true
-}
-
-func (u *staticUpstream) Exchanger() Exchanger { return u.ex }
-func (u *staticUpstream) From() string { return u.from }
-
-const max = 15
diff --git a/plugin/proxy/upstream_test.go b/plugin/proxy/upstream_test.go
deleted file mode 100644
index 3c788b882..000000000
--- a/plugin/proxy/upstream_test.go
+++ /dev/null
@@ -1,327 +0,0 @@
-package proxy
-
-import (
- "path/filepath"
- "strings"
- "testing"
-
- "github.com/coredns/coredns/plugin/test"
-
- "github.com/mholt/caddy"
-)
-
-func TestAllowedDomain(t *testing.T) {
- upstream := &staticUpstream{
- from: "miek.nl.",
- IgnoredSubDomains: []string{"download.miek.nl.", "static.miek.nl."}, // closing dot mandatory
- }
- tests := []struct {
- name string
- expected bool
- }{
- {"miek.nl.", true},
- {"download.miek.nl.", false},
- {"static.miek.nl.", false},
- {"blaat.miek.nl.", true},
- }
-
- for i, test := range tests {
- isAllowed := upstream.IsAllowedDomain(test.name)
- if test.expected != isAllowed {
- t.Errorf("Test %d: expected %v found %v for %s", i+1, test.expected, isAllowed, test.name)
- }
- }
-}
-
-func TestProxyParse(t *testing.T) {
- rmFunc, cert, key, ca := getPEMFiles(t)
- defer rmFunc()
-
- grpc1 := "proxy . 8.8.8.8:53 {\n protocol grpc " + ca + "\n}"
- grpc2 := "proxy . 8.8.8.8:53 {\n protocol grpc " + cert + " " + key + "\n}"
- grpc3 := "proxy . 8.8.8.8:53 {\n protocol grpc " + cert + " " + key + " " + ca + "\n}"
- grpc4 := "proxy . 8.8.8.8:53 {\n protocol grpc " + key + "\n}"
-
- tests := []struct {
- inputUpstreams string
- shouldErr bool
- }{
- {
- `proxy . 8.8.8.8:53`,
- false,
- },
- {
- `proxy 10.0.0.0/24 8.8.8.8:53`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- policy round_robin
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- fail_timeout 5s
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- max_fails 10
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- health_check /health:8080
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- except miek.nl example.org 10.0.0.0/24
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- spray
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- error_option
-}`,
- true,
- },
- {
- `
-proxy . some_bogus_filename`,
- true,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- protocol dns
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- protocol grpc
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- protocol grpc insecure
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- protocol dns force_tcp
-}`,
- false,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- protocol grpc a b c d
-}`,
- true,
- },
- {
- grpc1,
- false,
- },
- {
- grpc2,
- false,
- },
- {
- grpc3,
- false,
- },
- {
- grpc4,
- true,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- protocol foobar
-}`,
- true,
- },
- {
- `proxy`,
- true,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- protocol foobar
-}`,
- true,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- policy
-}`,
- true,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- fail_timeout
-}`,
- true,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- fail_timeout junky
-}`,
- true,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- health_check
-}`,
- true,
- },
- {
- `
-proxy . 8.8.8.8:53 {
- protocol dns force
-}`,
- true,
- },
- }
- for i, test := range tests {
- c := caddy.NewTestController("dns", test.inputUpstreams)
- _, err := NewStaticUpstreams(&c.Dispenser)
- if (err != nil) != test.shouldErr {
- t.Errorf("Test %d expected no error, got %v for %s", i+1, err, test.inputUpstreams)
- }
- }
-}
-
-func TestResolvParse(t *testing.T) {
- tests := []struct {
- inputUpstreams string
- filedata string
- shouldErr bool
- expected []string
- }{
- {
- `
-proxy . FILE
-`,
- `
-nameserver 1.2.3.4
-nameserver 4.3.2.1
-`,
- false,
- []string{"1.2.3.4:53", "4.3.2.1:53"},
- },
- {
- `
-proxy example.com 1.1.1.1:5000
-proxy . FILE
-proxy example.org 2.2.2.2:1234
-`,
- `
-nameserver 1.2.3.4
-`,
- false,
- []string{"1.1.1.1:5000", "1.2.3.4:53", "2.2.2.2:1234"},
- },
- {
- `
-proxy example.com 1.1.1.1:5000
-proxy . FILE
-proxy example.org 2.2.2.2:1234
-`,
- `
-junky resolv.conf
-`,
- false,
- []string{"1.1.1.1:5000", "2.2.2.2:1234"},
- },
- }
- for i, tc := range tests {
-
- path, rm, err := test.TempFile(".", tc.filedata)
- if err != nil {
- t.Fatalf("Test %d could not create temp file %v", i, err)
- }
- defer rm()
-
- config := strings.Replace(tc.inputUpstreams, "FILE", path, -1)
- c := caddy.NewTestController("dns", config)
- upstreams, err := NewStaticUpstreams(&c.Dispenser)
- if (err != nil) != tc.shouldErr {
- t.Errorf("Test %d expected no error, got %v", i+1, err)
- }
- var hosts []string
- for _, u := range upstreams {
- for _, h := range u.(*staticUpstream).Hosts {
- hosts = append(hosts, h.Name)
- }
- }
- if !tc.shouldErr {
- if len(hosts) != len(tc.expected) {
- t.Errorf("Test %d expected %d hosts got %d", i+1, len(tc.expected), len(upstreams))
- } else {
- ok := true
- for i, v := range tc.expected {
- if v != hosts[i] {
- ok = false
- }
- }
- if !ok {
- t.Errorf("Test %d expected %v got %v", i+1, tc.expected, upstreams)
- }
- }
- }
- }
-}
-
-func TestMaxTo(t *testing.T) {
- // Has 16 IP addresses.
- config := `proxy . 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1`
- c := caddy.NewTestController("dns", config)
- _, err := NewStaticUpstreams(&c.Dispenser)
- if err == nil {
- t.Error("Expected to many TOs configured, but nil")
- }
-}
-
-func getPEMFiles(t *testing.T) (rmFunc func(), cert, key, ca string) {
- tempDir, rmFunc, err := test.WritePEMFiles("")
- if err != nil {
- t.Fatalf("Could not write PEM files: %s", err)
- }
-
- cert = filepath.Join(tempDir, "cert.pem")
- key = filepath.Join(tempDir, "key.pem")
- ca = filepath.Join(tempDir, "ca.pem")
-
- return
-}
diff --git a/plugin/template/README.md b/plugin/template/README.md
index be099e70c..d52b51656 100644
--- a/plugin/template/README.md
+++ b/plugin/template/README.md
@@ -92,7 +92,7 @@ The `.invalid` domain is a reserved TLD (see [RFC 2606 Reserved Top Level DNS Na
~~~ corefile
. {
- proxy . 8.8.8.8
+ forward . 8.8.8.8
template ANY ANY invalid {
rcode NXDOMAIN
@@ -116,7 +116,7 @@ path (`dc1.example.com`) added.
~~~ corefile
. {
- proxy . 8.8.8.8
+ forward . 8.8.8.8
template IN ANY example.com.dc1.example.com {
rcode NXDOMAIN
@@ -129,7 +129,7 @@ A more verbose regex based equivalent would be
~~~ corefile
. {
- proxy . 8.8.8.8
+ forward . 8.8.8.8
template IN ANY example.com {
match "example\.com\.(dc1\.example\.com\.)$"
@@ -146,7 +146,7 @@ The regex-based version can do more complex matching/templating while zone-based
~~~ corefile
. {
- proxy . 8.8.8.8
+ forward . 8.8.8.8
# ip-a-b-c-d.example A a.b.c.d
@@ -178,7 +178,7 @@ Fallthrough is needed for mixed domains where only some responses are templated.
~~~ corefile
. {
- proxy . 8.8.8.8
+ forward . 8.8.8.8
template IN A example {
match "^ip-(?P<a>10)-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]dc[.]example[.]$"
@@ -195,7 +195,7 @@ Named capture groups can be used to template one response for multiple patterns.
~~~ corefile
. {
- proxy . 8.8.8.8
+ forward . 8.8.8.8
template IN A example {
match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
@@ -215,7 +215,7 @@ Named capture groups can be used to template one response for multiple patterns.
~~~ corefile
. {
- proxy . 8.8.8.8
+ forward . 8.8.8.8
template IN A example {
match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
diff --git a/plugin/tls/README.md b/plugin/tls/README.md
index 8a985cec7..244984750 100644
--- a/plugin/tls/README.md
+++ b/plugin/tls/README.md
@@ -10,9 +10,6 @@ CoreDNS supports queries that are encrypted using TLS (DNS over Transport Layer
or are using gRPC (https://grpc.io/, not an IETF standard). Normally DNS traffic isn't encrypted at
all (DNSSEC only signs resource records).
-The *proxy* plugin also support gRPC (`protocol gRPC`), meaning you can chain CoreDNS servers
-using this protocol.
-
The *tls* "plugin" allows you to configure the cryptographic keys that are needed for both
DNS-over-TLS and DNS-over-gRPC. If the `tls` directive is omitted, then no encryption takes place.
@@ -35,7 +32,7 @@ nameservers defined in `/etc/resolv.conf` to resolve the query. This proxy path
~~~
tls://.:5553 {
tls cert.pem key.pem ca.pem
- proxy . /etc/resolv.conf
+ forward . /etc/resolv.conf
}
~~~
@@ -45,7 +42,7 @@ incoming queries.
~~~
grpc://. {
tls cert.pem key.pem ca.pem
- proxy . /etc/resolv.conf
+ forward . /etc/resolv.conf
}
~~~