diff options
author | 2019-03-14 08:12:28 +0100 | |
---|---|---|
committer | 2019-03-14 07:12:28 +0000 | |
commit | 7b6cb76237d151ffa056c742ec281a17548fa089 (patch) | |
tree | 2100dd26d9e41f0be6fb365de9aeb334d7a94075 /plugin/grpc/grpc.go | |
parent | 0d8e1cf8b4ac157ef08837d0ff1e83597b8d1211 (diff) | |
download | coredns-7b6cb76237d151ffa056c742ec281a17548fa089.tar.gz coredns-7b6cb76237d151ffa056c742ec281a17548fa089.tar.zst coredns-7b6cb76237d151ffa056c742ec281a17548fa089.zip |
plugin/grpc: New gRPC plugin (#2667)
* plugin/grpc: New gRPC plugin
* some changes after the first review:
- remove healthcheck. gRPC already has this implicitly implemented
- some naming and stetic changes
- fix some comments
- other minor fixes
* plugin/grpc: New gRPC plugin
* some changes after the first review:
- remove healthcheck. gRPC already has this implicitly implemented
- some naming and stetic changes
- fix some comments
- other minor fixes
* add OWNERS file and change plugin order
* remove Rcode checker
Diffstat (limited to 'plugin/grpc/grpc.go')
-rw-r--r-- | plugin/grpc/grpc.go | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/plugin/grpc/grpc.go b/plugin/grpc/grpc.go new file mode 100644 index 000000000..655be00c1 --- /dev/null +++ b/plugin/grpc/grpc.go @@ -0,0 +1,130 @@ +package grpc + +import ( + "context" + "crypto/tls" + "time" + + "github.com/coredns/coredns/plugin" + "github.com/coredns/coredns/plugin/debug" + "github.com/coredns/coredns/request" + + "github.com/miekg/dns" + ot "github.com/opentracing/opentracing-go" +) + +// GRPC represents a plugin instance that can proxy requests to another (DNS) server via gRPC protocol. +// It has a list of proxies each representing one upstream proxy. +type GRPC struct { + proxies []*Proxy + p Policy + + from string + ignored []string + + tlsConfig *tls.Config + tlsServerName string + + Next plugin.Handler +} + +// ServeDNS implements the plugin.Handler interface. +func (g *GRPC) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + state := request.Request{W: w, Req: r} + if !g.match(state) { + return plugin.NextOrFailure(g.Name(), g.Next, ctx, w, r) + } + + var ( + span, child ot.Span + ret *dns.Msg + err error + i int + ) + span = ot.SpanFromContext(ctx) + list := g.list() + deadline := time.Now().Add(defaultTimeout) + + for time.Now().Before(deadline) { + if i >= len(list) { + // reached the end of list without any answer + if ret != nil { + // write empty response and finish + w.WriteMsg(ret) + } + break + } + + proxy := list[i] + i++ + + if span != nil { + child = span.Tracer().StartSpan("query", ot.ChildOf(span.Context())) + ctx = ot.ContextWithSpan(ctx, child) + } + + ret, err = proxy.query(ctx, r) + if err != nil { + // Continue with the next proxy + continue + } + + if child != nil { + child.Finish() + } + + // Check if the reply is correct; if not return FormErr. + if !state.Match(ret) { + debug.Hexdumpf(ret, "Wrong reply for id: %d, %s %d", ret.Id, state.QName(), state.QType()) + + formerr := state.ErrorMessage(dns.RcodeFormatError) + w.WriteMsg(formerr) + return 0, nil + } + + w.WriteMsg(ret) + return 0, nil + } + + return 0, nil +} + +// NewGRPC returns a new GRPC. +func newGRPC() *GRPC { + g := &GRPC{ + p: new(random), + } + return g +} + +// Name implements the Handler interface. +func (g *GRPC) Name() string { return "grpc" } + +// Len returns the number of configured proxies. +func (g *GRPC) len() int { return len(g.proxies) } + +func (g *GRPC) match(state request.Request) bool { + if !plugin.Name(g.from).Matches(state.Name()) || !g.isAllowedDomain(state.Name()) { + return false + } + + return true +} + +func (g *GRPC) isAllowedDomain(name string) bool { + if dns.Name(name) == dns.Name(g.from) { + return true + } + + for _, ignore := range g.ignored { + if plugin.Name(ignore).Matches(name) { + return false + } + } + return true +} + +// List returns a set of proxies to be used for this client depending on the policy in p. +func (g *GRPC) list() []*Proxy { return g.p.List(g.proxies) } + +const defaultTimeout = 5 * time.Second |