mirror of
https://github.com/coredns/coredns.git
synced 2025-11-23 20:24:02 -05:00
core: add more transports (#574)
* core: add listening for other protocols
Allow CoreDNS to listen for TLS request coming over port 853. This can
be enabled with `tls://` in the config file.
Implement listening for grps:// as well.
a Corefile like:
~~~
. tls://.:1853 {
whoami
tls
}
~~~
Means we listen on 1853 for tls requests, the `tls` config item allows
configuration for TLS parameters. We *might* be tempted to use Caddy's
Let's Encrypt implementation here.
* Refactor coredns/grpc into CoreDNS
This makes gRPC a first class citizen in CoreDNS. Add defines as being
just another server.
* some cleanups
* unexport the servers
* Move protobuf dir
* Hook up TLS properly
* Fix test
* listen for TLS as well. README updates
* disable test, fix package
* fix test
* Fix tests
* Fix remaining test
* Some tests
* Make the test work
* Add grpc test from #580
* fix crash
* Fix tests
* Close conn
* README cleanups
* README
* link RFC
This commit is contained in:
@@ -38,7 +38,7 @@ func (e *Erratic) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
|
||||
m.Authoritative = true
|
||||
|
||||
// small dance to copy rrA or rrAAAA into a non-pointer var that allows us to overwrite the ownername
|
||||
// in a non-racy manor.
|
||||
// in a non-racy way.
|
||||
switch state.QType() {
|
||||
case dns.TypeA:
|
||||
rr := *(rrA.(*dns.A))
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// See core/dnsserver/address.go - we should unify these two impls.
|
||||
|
||||
// Zones respresents a lists of zone names.
|
||||
type Zones []string
|
||||
|
||||
@@ -56,12 +58,24 @@ type (
|
||||
)
|
||||
|
||||
// Normalize will return the host portion of host, stripping
|
||||
// of any port. The host will also be fully qualified and lowercased.
|
||||
// of any port or transport. The host will also be fully qualified and lowercased.
|
||||
func (h Host) Normalize() string {
|
||||
|
||||
s := string(h)
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(s, TransportTLS+"://"):
|
||||
s = s[len(TransportTLS+"://"):]
|
||||
case strings.HasPrefix(s, TransportDNS+"://"):
|
||||
s = s[len(TransportDNS+"://"):]
|
||||
case strings.HasPrefix(s, TransportGRPC+"://"):
|
||||
s = s[len(TransportGRPC+"://"):]
|
||||
}
|
||||
|
||||
// separate host and port
|
||||
host, _, err := net.SplitHostPort(string(h))
|
||||
host, _, err := net.SplitHostPort(s)
|
||||
if err != nil {
|
||||
host, _, _ = net.SplitHostPort(string(h) + ":")
|
||||
host, _, _ = net.SplitHostPort(s + ":")
|
||||
}
|
||||
return Name(host).Normalize()
|
||||
}
|
||||
@@ -77,3 +91,10 @@ func (a Addr) Normalize() string {
|
||||
// TODO(miek): lowercase it?
|
||||
return net.JoinHostPort(addr, port)
|
||||
}
|
||||
|
||||
// Duplicated from core/dnsserver/address.go !
|
||||
const (
|
||||
TransportDNS = "dns"
|
||||
TransportTLS = "tls"
|
||||
TransportGRPC = "grpc"
|
||||
)
|
||||
|
||||
@@ -5,16 +5,13 @@ import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
|
||||
|
||||
"github.com/coredns/coredns/middleware/proxy/pb"
|
||||
"github.com/coredns/coredns/middleware/trace"
|
||||
"github.com/coredns/coredns/pb"
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: dns.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package pb is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
dns.proto
|
||||
|
||||
It has these top-level messages:
|
||||
DnsPacket
|
||||
*/
|
||||
package pb
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
import (
|
||||
context "golang.org/x/net/context"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type DnsPacket struct {
|
||||
Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
|
||||
}
|
||||
|
||||
func (m *DnsPacket) Reset() { *m = DnsPacket{} }
|
||||
func (m *DnsPacket) String() string { return proto.CompactTextString(m) }
|
||||
func (*DnsPacket) ProtoMessage() {}
|
||||
func (*DnsPacket) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func (m *DnsPacket) GetMsg() []byte {
|
||||
if m != nil {
|
||||
return m.Msg
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*DnsPacket)(nil), "coredns.dns.DnsPacket")
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// Client API for DnsService service
|
||||
|
||||
type DnsServiceClient interface {
|
||||
Query(ctx context.Context, in *DnsPacket, opts ...grpc.CallOption) (*DnsPacket, error)
|
||||
}
|
||||
|
||||
type dnsServiceClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewDnsServiceClient(cc *grpc.ClientConn) DnsServiceClient {
|
||||
return &dnsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *dnsServiceClient) Query(ctx context.Context, in *DnsPacket, opts ...grpc.CallOption) (*DnsPacket, error) {
|
||||
out := new(DnsPacket)
|
||||
err := grpc.Invoke(ctx, "/coredns.dns.DnsService/Query", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for DnsService service
|
||||
|
||||
type DnsServiceServer interface {
|
||||
Query(context.Context, *DnsPacket) (*DnsPacket, error)
|
||||
}
|
||||
|
||||
func RegisterDnsServiceServer(s *grpc.Server, srv DnsServiceServer) {
|
||||
s.RegisterService(&_DnsService_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _DnsService_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DnsPacket)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DnsServiceServer).Query(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/coredns.dns.DnsService/Query",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DnsServiceServer).Query(ctx, req.(*DnsPacket))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _DnsService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "coredns.dns.DnsService",
|
||||
HandlerType: (*DnsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Query",
|
||||
Handler: _DnsService_Query_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "dns.proto",
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("dns.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 120 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4c, 0xc9, 0x2b, 0xd6,
|
||||
0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x4e, 0xce, 0x2f, 0x4a, 0x05, 0x71, 0x53, 0xf2, 0x8a,
|
||||
0x95, 0x64, 0xb9, 0x38, 0x5d, 0xf2, 0x8a, 0x03, 0x12, 0x93, 0xb3, 0x53, 0x4b, 0x84, 0x04, 0xb8,
|
||||
0x98, 0x73, 0x8b, 0xd3, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0x40, 0x4c, 0x23, 0x57, 0x2e,
|
||||
0x2e, 0x97, 0xbc, 0xe2, 0xe0, 0xd4, 0xa2, 0xb2, 0xcc, 0xe4, 0x54, 0x21, 0x73, 0x2e, 0xd6, 0xc0,
|
||||
0xd2, 0xd4, 0xa2, 0x4a, 0x21, 0x31, 0x3d, 0x24, 0x33, 0xf4, 0xe0, 0x06, 0x48, 0xe1, 0x10, 0x77,
|
||||
0x62, 0x89, 0x62, 0x2a, 0x48, 0x4a, 0x62, 0x03, 0xdb, 0x6f, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff,
|
||||
0xf5, 0xd1, 0x3f, 0x26, 0x8c, 0x00, 0x00, 0x00,
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package coredns.dns;
|
||||
option go_package = "pb";
|
||||
|
||||
message DnsPacket {
|
||||
bytes msg = 1;
|
||||
}
|
||||
|
||||
service DnsService {
|
||||
rpc Query (DnsPacket) returns (DnsPacket);
|
||||
}
|
||||
@@ -40,8 +40,7 @@ func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) {
|
||||
zones := make([]string, len(c.ServerBlockKeys))
|
||||
|
||||
for i, str := range c.ServerBlockKeys {
|
||||
host, _, _ := net.SplitHostPort(str)
|
||||
zones[i] = strings.ToLower(host)
|
||||
zones[i] = middleware.Host(str).Normalize()
|
||||
}
|
||||
|
||||
for c.Next() {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/middleware"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
)
|
||||
@@ -21,7 +22,7 @@ func setup(c *caddy.Controller) error {
|
||||
|
||||
for c.Next() {
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
return middleware.Error("root", c.ArgErr())
|
||||
}
|
||||
config.Root = c.Val()
|
||||
}
|
||||
@@ -34,7 +35,7 @@ func setup(c *caddy.Controller) error {
|
||||
// But make sure the user knows!
|
||||
log.Printf("[WARNING] Root path does not exist: %s", config.Root)
|
||||
} else {
|
||||
return c.Errf("Unable to access root path '%s': %v", config.Root, err)
|
||||
return middleware.Error("root", c.Errf("unable to access root path '%s': %v", config.Root, err))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ func TestRoot(t *testing.T) {
|
||||
|
||||
// Predefined error substrings
|
||||
parseErrContent := "Parse error:"
|
||||
unableToAccessErrContent := "Unable to access root path"
|
||||
unableToAccessErrContent := "unable to access root path"
|
||||
|
||||
existingDirPath, err := getTempDirPath()
|
||||
if err != nil {
|
||||
|
||||
13
middleware/tls/README.md
Normal file
13
middleware/tls/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# tls
|
||||
|
||||
*tls* extra TLS configuration.
|
||||
|
||||
## Syntax
|
||||
|
||||
~~~ txt
|
||||
tls [STUFF]
|
||||
~~~
|
||||
|
||||
**STUFF** is things you'll need to configure TLS.
|
||||
|
||||
## Examples
|
||||
37
middleware/tls/tls.go
Normal file
37
middleware/tls/tls.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package tls
|
||||
|
||||
import (
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/middleware"
|
||||
"github.com/coredns/coredns/middleware/pkg/tls"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterPlugin("tls", caddy.Plugin{
|
||||
ServerType: "dns",
|
||||
Action: setup,
|
||||
})
|
||||
}
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
config := dnsserver.GetConfig(c)
|
||||
|
||||
if config.TLSConfig != nil {
|
||||
return middleware.Error("tls", c.Errf("TLS already configured for this server instance"))
|
||||
}
|
||||
|
||||
for c.Next() {
|
||||
args := c.RemainingArgs()
|
||||
if len(args) != 3 {
|
||||
return middleware.Error("tls", c.ArgErr())
|
||||
}
|
||||
tls, err := tls.NewTLSConfig(args[0], args[1], args[2])
|
||||
if err != nil {
|
||||
return middleware.Error("tls", c.ArgErr())
|
||||
}
|
||||
config.TLSConfig = tls
|
||||
}
|
||||
return nil
|
||||
}
|
||||
44
middleware/tls/tls_test.go
Normal file
44
middleware/tls/tls_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package tls
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
)
|
||||
|
||||
func TestTLS(t *testing.T) {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
|
||||
tests := []struct {
|
||||
input string
|
||||
shouldErr bool
|
||||
expectedRoot string // expected root, set to the controller. Empty for negative cases.
|
||||
expectedErrContent string // substring from the expected error. Empty for positive cases.
|
||||
}{
|
||||
// positive
|
||||
// negative
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
c := caddy.NewTestController("dns", test.input)
|
||||
err := setup(c)
|
||||
//cfg := dnsserver.GetConfig(c)
|
||||
|
||||
if test.shouldErr && err == nil {
|
||||
t.Errorf("Test %d: Expected error but found %s for input %s", i, err, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user