| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | package dnsserver
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2018-04-20 11:01:06 +01:00
										 |  |  | 	"context"
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	"crypto/tls"
 | 
					
						
							|  |  |  | 	"errors"
 | 
					
						
							|  |  |  | 	"fmt"
 | 
					
						
							|  |  |  | 	"net"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-21 12:34:02 +01:00
										 |  |  | 	"github.com/coredns/coredns/pb"
 | 
					
						
							| 
									
										
										
										
											2019-11-17 02:02:46 +00:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/reuseport"
 | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/transport"
 | 
					
						
							| 
									
										
										
										
											2018-06-21 12:34:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:25:07 +08:00
										 |  |  | 	"github.com/caddyserver/caddy"
 | 
					
						
							| 
									
										
										
										
											2017-04-18 11:10:49 -04:00
										 |  |  | 	"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	"github.com/miekg/dns"
 | 
					
						
							| 
									
										
										
										
											2018-01-14 03:09:14 -05:00
										 |  |  | 	"github.com/opentracing/opentracing-go"
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	"google.golang.org/grpc"
 | 
					
						
							|  |  |  | 	"google.golang.org/grpc/peer"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | // ServergRPC represents an instance of a DNS-over-gRPC server.
 | 
					
						
							|  |  |  | type ServergRPC struct {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	*Server
 | 
					
						
							|  |  |  | 	grpcServer *grpc.Server
 | 
					
						
							|  |  |  | 	listenAddr net.Addr
 | 
					
						
							| 
									
										
										
										
											2018-01-14 03:09:14 -05:00
										 |  |  | 	tlsConfig  *tls.Config
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | // NewServergRPC returns a new CoreDNS GRPC server and compiles all plugin in to it.
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | func NewServergRPC(addr string, group []*Config) (*ServergRPC, error) {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	s, err := NewServer(addr, group)
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2018-01-14 03:09:14 -05:00
										 |  |  | 	// The *tls* plugin must make sure that multiple conflicting
 | 
					
						
							|  |  |  | 	// TLS configuration return an error: it can only be specified once.
 | 
					
						
							|  |  |  | 	var tlsConfig *tls.Config
 | 
					
						
							|  |  |  | 	for _, conf := range s.zones {
 | 
					
						
							|  |  |  | 		// Should we error if some configs *don't* have TLS?
 | 
					
						
							|  |  |  | 		tlsConfig = conf.TLSConfig
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 14:46:53 +00:00
										 |  |  | 	return &ServergRPC{Server: s, tlsConfig: tlsConfig}, nil
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:25:07 +08:00
										 |  |  | // Compile-time check to ensure Server implements the caddy.GracefulServer interface
 | 
					
						
							|  |  |  | var _ caddy.GracefulServer = &Server{}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | // Serve implements caddy.TCPServer interface.
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | func (s *ServergRPC) Serve(l net.Listener) error {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	s.m.Lock()
 | 
					
						
							|  |  |  | 	s.listenAddr = l.Addr()
 | 
					
						
							|  |  |  | 	s.m.Unlock()
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-18 11:10:49 -04:00
										 |  |  | 	if s.Tracer() != nil {
 | 
					
						
							|  |  |  | 		onlyIfParent := func(parentSpanCtx opentracing.SpanContext, method string, req, resp interface{}) bool {
 | 
					
						
							|  |  |  | 			return parentSpanCtx != nil
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		intercept := otgrpc.OpenTracingServerInterceptor(s.Tracer(), otgrpc.IncludingSpans(onlyIfParent))
 | 
					
						
							|  |  |  | 		s.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(intercept))
 | 
					
						
							|  |  |  | 	} else {
 | 
					
						
							|  |  |  | 		s.grpcServer = grpc.NewServer()
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pb.RegisterDnsServiceServer(s.grpcServer, s)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-14 03:09:14 -05:00
										 |  |  | 	if s.tlsConfig != nil {
 | 
					
						
							|  |  |  | 		l = tls.NewListener(l, s.tlsConfig)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	return s.grpcServer.Serve(l)
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ServePacket implements caddy.UDPServer interface.
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | func (s *ServergRPC) ServePacket(p net.PacketConn) error { return nil }
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Listen implements caddy.TCPServer interface.
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | func (s *ServergRPC) Listen() (net.Listener, error) {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-17 02:02:46 +00:00
										 |  |  | 	l, err := reuseport.Listen("tcp", s.Addr[len(transport.GRPC+"://"):])
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return l, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListenPacket implements caddy.UDPServer interface.
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | func (s *ServergRPC) ListenPacket() (net.PacketConn, error) { return nil, nil }
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // OnStartupComplete lists the sites served by this server
 | 
					
						
							|  |  |  | // and any relevant information, assuming Quiet is false.
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | func (s *ServergRPC) OnStartupComplete() {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	if Quiet {
 | 
					
						
							|  |  |  | 		return
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | 	out := startUpZones(transport.GRPC+"://", s.Addr, s.zones)
 | 
					
						
							| 
									
										
										
										
											2018-03-17 19:04:01 +00:00
										 |  |  | 	if out != "" {
 | 
					
						
							|  |  |  | 		fmt.Print(out)
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 09:46:40 -07:00
										 |  |  | // Stop stops the server. It blocks until the server is
 | 
					
						
							|  |  |  | // totally stopped.
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | func (s *ServergRPC) Stop() (err error) {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	s.m.Lock()
 | 
					
						
							|  |  |  | 	defer s.m.Unlock()
 | 
					
						
							|  |  |  | 	if s.grpcServer != nil {
 | 
					
						
							|  |  |  | 		s.grpcServer.GracefulStop()
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Query is the main entry-point into the gRPC server. From here we call ServeDNS like
 | 
					
						
							|  |  |  | // any normal server. We use a custom responseWriter to pick up the bytes we need to write
 | 
					
						
							|  |  |  | // back to the client as a protobuf.
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | func (s *ServergRPC) Query(ctx context.Context, in *pb.DnsPacket) (*pb.DnsPacket, error) {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	msg := new(dns.Msg)
 | 
					
						
							|  |  |  | 	err := msg.Unpack(in.Msg)
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p, ok := peer.FromContext(ctx)
 | 
					
						
							|  |  |  | 	if !ok {
 | 
					
						
							|  |  |  | 		return nil, errors.New("no peer in gRPC context")
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	a, ok := p.Addr.(*net.TCPAddr)
 | 
					
						
							|  |  |  | 	if !ok {
 | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("no TCP peer in gRPC context: %v", p.Addr)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-28 00:38:06 +03:00
										 |  |  | 	w := &gRPCresponse{localAddr: s.listenAddr, remoteAddr: a, Msg: msg}
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-27 17:52:48 +03:00
										 |  |  | 	dnsCtx := context.WithValue(ctx, Key{}, s.Server)
 | 
					
						
							|  |  |  | 	s.ServeDNS(dnsCtx, w, msg)
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	packed, err := w.Msg.Pack()
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &pb.DnsPacket{Msg: packed}, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 09:46:40 -07:00
										 |  |  | // Shutdown stops the server (non gracefully).
 | 
					
						
							| 
									
										
										
										
											2017-06-14 09:37:10 -07:00
										 |  |  | func (s *ServergRPC) Shutdown() error {
 | 
					
						
							| 
									
										
										
										
											2017-05-25 12:08:34 -07:00
										 |  |  | 	if s.grpcServer != nil {
 | 
					
						
							|  |  |  | 		s.grpcServer.Stop()
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type gRPCresponse struct {
 | 
					
						
							|  |  |  | 	localAddr  net.Addr
 | 
					
						
							|  |  |  | 	remoteAddr net.Addr
 | 
					
						
							|  |  |  | 	Msg        *dns.Msg
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Write is the hack that makes this work. It does not actually write the message
 | 
					
						
							| 
									
										
										
										
											2019-02-20 19:12:21 +07:00
										 |  |  | // but returns the bytes we need to write in r. We can then pick this up in Query
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | // and write a proper protobuf back to the client.
 | 
					
						
							|  |  |  | func (r *gRPCresponse) Write(b []byte) (int, error) {
 | 
					
						
							|  |  |  | 	r.Msg = new(dns.Msg)
 | 
					
						
							|  |  |  | 	return len(b), r.Msg.Unpack(b)
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // These methods implement the dns.ResponseWriter interface from Go DNS.
 | 
					
						
							|  |  |  | func (r *gRPCresponse) Close() error              { return nil }
 | 
					
						
							|  |  |  | func (r *gRPCresponse) TsigStatus() error         { return nil }
 | 
					
						
							| 
									
										
										
										
											2019-09-23 21:40:14 +08:00
										 |  |  | func (r *gRPCresponse) TsigTimersOnly(b bool)     {}
 | 
					
						
							|  |  |  | func (r *gRPCresponse) Hijack()                   {}
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | func (r *gRPCresponse) LocalAddr() net.Addr       { return r.localAddr }
 | 
					
						
							|  |  |  | func (r *gRPCresponse) RemoteAddr() net.Addr      { return r.remoteAddr }
 | 
					
						
							|  |  |  | func (r *gRPCresponse) WriteMsg(m *dns.Msg) error { r.Msg = m; return nil }
 |