Added CoreDNS plugin setup and replaced forward
This commit is contained in:
parent
9bc4bf66ed
commit
efdd1c1ff2
|
@ -253,7 +253,7 @@ const coreDNSConfigTemplate = `.:{{.Port}} {
|
||||||
hosts {
|
hosts {
|
||||||
fallthrough
|
fallthrough
|
||||||
}
|
}
|
||||||
{{if .UpstreamDNS}}forward . {{range .UpstreamDNS}}{{.}} {{end}}{{end}}
|
{{if .UpstreamDNS}}upstream {{range .UpstreamDNS}}{{.}} {{end}} { bootstrap 8.8.8.8:53 }{{end}}
|
||||||
{{.Cache}}
|
{{.Cache}}
|
||||||
{{.Prometheus}}
|
{{.Prometheus}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"sync" // Include all plugins.
|
"sync" // Include all plugins.
|
||||||
|
|
||||||
_ "github.com/AdguardTeam/AdGuardHome/coredns_plugin"
|
_ "github.com/AdguardTeam/AdGuardHome/coredns_plugin"
|
||||||
|
_ "github.com/AdguardTeam/AdGuardHome/upstream"
|
||||||
"github.com/coredns/coredns/core/dnsserver"
|
"github.com/coredns/coredns/core/dnsserver"
|
||||||
"github.com/coredns/coredns/coremain"
|
"github.com/coredns/coredns/coremain"
|
||||||
_ "github.com/coredns/coredns/plugin/auto"
|
_ "github.com/coredns/coredns/plugin/auto"
|
||||||
|
@ -79,6 +80,7 @@ var directives = []string{
|
||||||
"loop",
|
"loop",
|
||||||
"forward",
|
"forward",
|
||||||
"proxy",
|
"proxy",
|
||||||
|
"upstream",
|
||||||
"erratic",
|
"erratic",
|
||||||
"whoami",
|
"whoami",
|
||||||
"on",
|
"on",
|
||||||
|
|
|
@ -42,7 +42,20 @@ func NewDnsUpstream(endpoint string, proto string, tlsServerName string) (Upstre
|
||||||
// Exchange provides an implementation for the Upstream interface
|
// Exchange provides an implementation for the Upstream interface
|
||||||
func (u *DnsUpstream) Exchange(ctx context.Context, query *dns.Msg) (*dns.Msg, error) {
|
func (u *DnsUpstream) Exchange(ctx context.Context, query *dns.Msg) (*dns.Msg, error) {
|
||||||
|
|
||||||
resp, err := u.exchange(query)
|
resp, err := u.exchange(u.proto, query)
|
||||||
|
|
||||||
|
// Retry over TCP if response is truncated
|
||||||
|
if err == dns.ErrTruncated && u.proto == "udp" {
|
||||||
|
resp, err = u.exchange("tcp", query)
|
||||||
|
} else if err == dns.ErrTruncated && resp != nil {
|
||||||
|
// Reassemble something to be sent to client
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetReply(query)
|
||||||
|
m.Truncated = true
|
||||||
|
m.Authoritative = true
|
||||||
|
m.Rcode = dns.RcodeSuccess
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp = &dns.Msg{}
|
resp = &dns.Msg{}
|
||||||
|
@ -62,10 +75,10 @@ func (u *DnsUpstream) Close() error {
|
||||||
|
|
||||||
// Performs a synchronous query. It sends the message m via the conn
|
// Performs a synchronous query. It sends the message m via the conn
|
||||||
// c and waits for a reply. The conn c is not closed.
|
// c and waits for a reply. The conn c is not closed.
|
||||||
func (u *DnsUpstream) exchange(query *dns.Msg) (r *dns.Msg, err error) {
|
func (u *DnsUpstream) exchange(proto string, query *dns.Msg) (r *dns.Msg, err error) {
|
||||||
|
|
||||||
// Establish a connection if needed (or reuse cached)
|
// Establish a connection if needed (or reuse cached)
|
||||||
conn, err := u.transport.Dial(u.proto)
|
conn, err := u.transport.Dial(proto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ func IsAlive(u Upstream) (bool, error) {
|
||||||
ping := new(dns.Msg)
|
ping := new(dns.Msg)
|
||||||
ping.SetQuestion("ipv4only.arpa.", dns.TypeA)
|
ping.SetQuestion("ipv4only.arpa.", dns.TypeA)
|
||||||
|
|
||||||
resp, err := u.Exchange(nil, ping)
|
resp, err := u.Exchange(context.Background(), ping)
|
||||||
|
|
||||||
// If we got a header, we're alright, basically only care about I/O errors 'n stuff.
|
// If we got a header, we're alright, basically only care about I/O errors 'n stuff.
|
||||||
if err != nil && resp != nil {
|
if err != nil && resp != nil {
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
package upstream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/coredns/coredns/core/dnsserver"
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
"github.com/mholt/caddy"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
caddy.RegisterPlugin("upstream", caddy.Plugin{
|
||||||
|
ServerType: "dns",
|
||||||
|
Action: setup,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the configuration and initialize upstreams
|
||||||
|
func setup(c *caddy.Controller) error {
|
||||||
|
|
||||||
|
p, err := setupPlugin(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config := dnsserver.GetConfig(c)
|
||||||
|
config.AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||||
|
p.Next = next
|
||||||
|
return p
|
||||||
|
})
|
||||||
|
|
||||||
|
c.OnShutdown(p.onShutdown)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the configuration
|
||||||
|
func setupPlugin(c *caddy.Controller) (*UpstreamPlugin, error) {
|
||||||
|
|
||||||
|
p := New()
|
||||||
|
|
||||||
|
log.Println("Initializing the Upstream plugin")
|
||||||
|
|
||||||
|
bootstrap := ""
|
||||||
|
upstreamUrls := []string{}
|
||||||
|
for c.Next() {
|
||||||
|
args := c.RemainingArgs()
|
||||||
|
if len(args) > 0 {
|
||||||
|
upstreamUrls = append(upstreamUrls, args...)
|
||||||
|
}
|
||||||
|
for c.NextBlock() {
|
||||||
|
switch c.Val() {
|
||||||
|
case "bootstrap":
|
||||||
|
if !c.NextArg() {
|
||||||
|
return nil, c.ArgErr()
|
||||||
|
}
|
||||||
|
bootstrap = c.Val()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, url := range upstreamUrls {
|
||||||
|
u, err := NewUpstream(url, bootstrap)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Cannot initialize upstream %s", url)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Upstreams = append(p.Upstreams, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *UpstreamPlugin) onShutdown() error {
|
||||||
|
for i := range p.Upstreams {
|
||||||
|
|
||||||
|
u := p.Upstreams[i]
|
||||||
|
err := u.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error while closing the upstream: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package upstream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mholt/caddy"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetup(t *testing.T) {
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
config string
|
||||||
|
}{
|
||||||
|
{`upstream 8.8.8.8`},
|
||||||
|
{`upstream 8.8.8.8 {
|
||||||
|
bootstrap 8.8.8.8:53
|
||||||
|
}`},
|
||||||
|
{`upstream tls://1.1.1.1 8.8.8.8 {
|
||||||
|
bootstrap 1.1.1.1
|
||||||
|
}`},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
c := caddy.NewTestController("dns", test.config)
|
||||||
|
err := setup(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"log"
|
|
||||||
"runtime"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,8 +12,6 @@ const (
|
||||||
defaultTimeout = 5 * time.Second
|
defaultTimeout = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Add a helper method for health-checking an upstream (see health.go in coredns)
|
|
||||||
|
|
||||||
// Upstream is a simplified interface for proxy destination
|
// Upstream is a simplified interface for proxy destination
|
||||||
type Upstream interface {
|
type Upstream interface {
|
||||||
Exchange(ctx context.Context, query *dns.Msg) (*dns.Msg, error)
|
Exchange(ctx context.Context, query *dns.Msg) (*dns.Msg, error)
|
||||||
|
@ -30,10 +26,10 @@ type UpstreamPlugin struct {
|
||||||
|
|
||||||
// Initialize the upstream plugin
|
// Initialize the upstream plugin
|
||||||
func New() *UpstreamPlugin {
|
func New() *UpstreamPlugin {
|
||||||
p := &UpstreamPlugin{}
|
p := &UpstreamPlugin{
|
||||||
|
Upstreams: []Upstream{},
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure all resources are cleaned up
|
|
||||||
runtime.SetFinalizer(p, (*UpstreamPlugin).finalizer)
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,15 +52,3 @@ func (p *UpstreamPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *
|
||||||
|
|
||||||
// Name implements interface for CoreDNS plugin
|
// Name implements interface for CoreDNS plugin
|
||||||
func (p *UpstreamPlugin) Name() string { return "upstream" }
|
func (p *UpstreamPlugin) Name() string { return "upstream" }
|
||||||
|
|
||||||
func (p *UpstreamPlugin) finalizer() {
|
|
||||||
|
|
||||||
for i := range p.Upstreams {
|
|
||||||
|
|
||||||
u := p.Upstreams[i]
|
|
||||||
err := u.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error while closing the upstream: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ package upstream
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
"golang.org/x/net/context"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -169,7 +170,7 @@ func testUpstream(t *testing.T, u Upstream) {
|
||||||
{Name: test.name, Qtype: dns.TypeA, Qclass: dns.ClassINET},
|
{Name: test.name, Qtype: dns.TypeA, Qclass: dns.ClassINET},
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := u.Exchange(nil, &req)
|
resp, err := u.Exchange(context.Background(), &req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error while making an upstream request: %s", err)
|
t.Errorf("error while making an upstream request: %s", err)
|
||||||
|
|
Loading…
Reference in New Issue