AdGuardDNS/info/info.go
2020-08-17 21:16:03 +03:00

130 lines
3.0 KiB
Go

package info
import (
"context"
"fmt"
"net"
"strings"
"github.com/AdguardTeam/AdGuardDNS/util"
clog "github.com/coredns/coredns/plugin/pkg/log"
"github.com/coredns/coredns/request"
"github.com/coredns/coredns/plugin"
"github.com/miekg/dns"
)
type info struct {
Next plugin.Handler
domain string // etld domain name for the check DNS requests
protocol string // protocol (can be auto, dns, doh, dot, dnscrypt)
serverType string // server type (arbitrary string)
canary string // canary domain
addrs4 []net.IP // list of IPv4 addresses to return in response to an A check request
addrs6 []net.IP // list of IPv4 addresses to return in response to an AAAA check request
}
// Name returns name of the plugin as seen in Corefile and plugin.cfg
func (i *info) Name() string { return "info" }
// ServeDNS handles the DNS request and refuses if it's an ANY request
func (i *info) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
if len(r.Question) != 1 {
// google DNS, bind and others do the same
return dns.RcodeFormatError, fmt.Errorf("got DNS request with != 1 questions")
}
question := r.Question[0]
host := strings.ToLower(strings.TrimSuffix(question.Name, "."))
if i.canary != "" && host == i.canary {
return i.writeAnswer(w, r)
}
protocol := i.getProtocol(ctx)
checkDomain := fmt.Sprintf("-%s-%s-dnscheck.%s", protocol, i.serverType, i.domain)
if strings.HasSuffix(host, checkDomain) {
return i.writeAnswer(w, r)
}
return plugin.NextOrFailure(i.Name(), i.Next, ctx, w, r)
}
func (i *info) getProtocol(ctx context.Context) string {
if i.protocol == "auto" {
addr := util.GetServer(ctx)
if strings.HasPrefix(addr, "tls") {
return "dot"
} else if strings.HasPrefix(addr, "https") {
return "doh"
}
return "dns"
}
return i.protocol
}
func (i *info) writeAnswer(w dns.ResponseWriter, r *dns.Msg) (int, error) {
state := request.Request{W: w, Req: r}
m := i.genAnswer(r)
state.SizeAndDo(m)
err := state.W.WriteMsg(m)
if err != nil {
clog.Infof("Got error %s\n", err)
return dns.RcodeServerFailure, err
}
return m.Rcode, nil
}
func (i *info) genAnswer(r *dns.Msg) *dns.Msg {
m := new(dns.Msg)
m.SetRcode(r, dns.RcodeSuccess)
qType := r.Question[0].Qtype
if qType == dns.TypeA && len(i.addrs4) > 0 {
for _, ip := range i.addrs4 {
m.Answer = append(m.Answer, i.genA(r, ip))
}
} else if qType == dns.TypeAAAA && len(i.addrs6) > 0 {
for _, ip := range i.addrs6 {
m.Answer = append(m.Answer, i.genAAAA(r, ip))
}
}
m.RecursionAvailable = true
m.Compress = true
return m
}
func (i *info) genA(r *dns.Msg, ip net.IP) *dns.A {
answer := new(dns.A)
answer.Hdr = dns.RR_Header{
Name: r.Question[0].Name,
Rrtype: dns.TypeA,
Ttl: 100,
Class: dns.ClassINET,
}
answer.A = ip
return answer
}
func (i *info) genAAAA(r *dns.Msg, ip net.IP) *dns.AAAA {
answer := new(dns.AAAA)
answer.Hdr = dns.RR_Header{
Name: r.Question[0].Name,
Rrtype: dns.TypeAAAA,
Ttl: 100,
Class: dns.ClassINET,
}
answer.AAAA = ip
return answer
}