2020-01-25 17:43:02 +00:00
|
|
|
package resolver
|
2013-07-23 11:10:38 +00:00
|
|
|
|
|
|
|
import (
|
2020-01-25 17:43:02 +00:00
|
|
|
"errors"
|
2013-07-23 11:10:38 +00:00
|
|
|
"fmt"
|
2021-04-15 03:42:24 +00:00
|
|
|
log "github.com/sirupsen/logrus"
|
2021-04-15 05:04:58 +00:00
|
|
|
"github.com/spf13/viper"
|
|
|
|
"io"
|
2020-01-25 17:43:02 +00:00
|
|
|
"meow.tf/joker/godns/utils"
|
2018-02-01 09:43:28 +00:00
|
|
|
"net"
|
2015-02-03 14:53:57 +00:00
|
|
|
"os"
|
2013-07-23 16:37:38 +00:00
|
|
|
"strings"
|
2015-02-12 09:19:46 +00:00
|
|
|
"sync"
|
2013-07-23 11:10:38 +00:00
|
|
|
"time"
|
2015-02-10 09:00:59 +00:00
|
|
|
|
2018-07-02 00:47:22 +00:00
|
|
|
"crypto/tls"
|
2020-01-25 17:43:02 +00:00
|
|
|
"github.com/miekg/dns"
|
2013-07-23 11:10:38 +00:00
|
|
|
)
|
|
|
|
|
2013-07-23 16:37:38 +00:00
|
|
|
type ResolvError struct {
|
2015-02-12 09:19:46 +00:00
|
|
|
qname, net string
|
2021-04-15 03:42:24 +00:00
|
|
|
nameservers []*Nameserver
|
2013-07-23 16:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (e ResolvError) Error() string {
|
2021-04-15 03:42:24 +00:00
|
|
|
nameservers := make([]string, len(e.nameservers))
|
|
|
|
|
|
|
|
for i, nameserver := range e.nameservers {
|
|
|
|
nameservers[i] = nameserver.address
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s resolv failed on %s (%s)", e.qname, strings.Join(nameservers, "; "), e.net)
|
2013-07-23 16:37:38 +00:00
|
|
|
}
|
|
|
|
|
2018-02-01 10:30:41 +00:00
|
|
|
type RResp struct {
|
|
|
|
msg *dns.Msg
|
2021-04-15 03:42:24 +00:00
|
|
|
nameserver *Nameserver
|
2018-02-01 10:30:41 +00:00
|
|
|
rtt time.Duration
|
|
|
|
}
|
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
// Resolver contains a list of nameservers, domain-specific nameservers, and dns clients
|
2013-07-23 11:10:38 +00:00
|
|
|
type Resolver struct {
|
2021-04-15 03:42:24 +00:00
|
|
|
servers []*Nameserver
|
|
|
|
domainServer *suffixTreeNode
|
|
|
|
config *Settings
|
2018-07-02 00:47:22 +00:00
|
|
|
|
2020-01-25 17:43:02 +00:00
|
|
|
clients map[string]*dns.Client
|
|
|
|
clientLock sync.RWMutex
|
2015-02-03 14:53:57 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
// NewResolver initializes a resolver from the specified settings
|
2020-02-08 03:38:22 +00:00
|
|
|
func NewResolver(c Settings) *Resolver {
|
2015-02-04 08:21:08 +00:00
|
|
|
r := &Resolver{
|
2021-04-15 03:42:24 +00:00
|
|
|
servers: make([]*Nameserver, 0),
|
|
|
|
domainServer: newSuffixTreeRoot(),
|
|
|
|
config: &c,
|
2015-02-03 14:53:57 +00:00
|
|
|
}
|
|
|
|
|
2018-08-05 03:53:11 +00:00
|
|
|
if len(c.ServerListFile) > 0 {
|
2021-04-15 05:04:58 +00:00
|
|
|
err := r.ReadServerListFile(c.ServerListFile)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Fatalln("Unable to read server list file")
|
|
|
|
}
|
2015-02-04 08:21:08 +00:00
|
|
|
}
|
2015-02-03 14:53:57 +00:00
|
|
|
|
2015-02-04 08:21:08 +00:00
|
|
|
if len(c.ResolvFile) > 0 {
|
|
|
|
clientConfig, err := dns.ClientConfigFromFile(c.ResolvFile)
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2015-02-04 08:21:08 +00:00
|
|
|
if err != nil {
|
2021-04-15 05:04:58 +00:00
|
|
|
log.WithError(err).Fatalln("not a valid resolv.conf file")
|
2015-02-04 08:21:08 +00:00
|
|
|
}
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2015-02-04 08:21:08 +00:00
|
|
|
for _, server := range clientConfig.Servers {
|
2021-04-15 03:42:24 +00:00
|
|
|
r.servers = append(r.servers, &Nameserver{net: "udp", address: net.JoinHostPort(server, clientConfig.Port)})
|
2015-02-04 08:21:08 +00:00
|
|
|
}
|
2015-02-03 14:53:57 +00:00
|
|
|
}
|
2015-02-04 08:21:08 +00:00
|
|
|
|
2015-02-03 14:53:57 +00:00
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
// server is a configuration struct for server lists
|
|
|
|
type server struct {
|
|
|
|
// Type is the nameserver type (https, udp, tcp-tls), optional
|
|
|
|
Type string
|
|
|
|
Server string
|
|
|
|
// Optional host for passing to TLS Config
|
|
|
|
Host string
|
|
|
|
Domains []string
|
|
|
|
}
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
// parseServerListFile loads a YAML server list file.
|
|
|
|
func (r *Resolver) parseServerListFile(buf io.Reader) error {
|
|
|
|
v := viper.New()
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
var err error
|
2015-02-03 14:53:57 +00:00
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
v.SetConfigType("yaml")
|
2015-02-03 14:53:57 +00:00
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
if err = v.ReadConfig(buf); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
list := make([]server, 0)
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
if err = v.UnmarshalKey("servers", &list); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
for _, server := range list {
|
|
|
|
nameserver := &Nameserver{
|
|
|
|
net: determineNet(server.Type, server.Server),
|
|
|
|
address: server.Server,
|
2015-02-03 14:53:57 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
if len(server.Domains) > 0 {
|
|
|
|
for _, domain := range server.Domains {
|
|
|
|
r.domainServer.sinsert(strings.Split(domain, "."), nameserver)
|
2015-02-04 08:21:08 +00:00
|
|
|
}
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
continue
|
2015-02-03 14:53:57 +00:00
|
|
|
}
|
2021-04-15 05:04:58 +00:00
|
|
|
|
|
|
|
r.servers = append(r.servers, nameserver)
|
2015-02-03 14:53:57 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
return nil
|
2013-07-23 11:10:38 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
// ReadServerListFile loads a list of server list files.
|
|
|
|
func (r *Resolver) ReadServerListFile(files []string) error {
|
2018-02-01 11:22:45 +00:00
|
|
|
for _, file := range files {
|
|
|
|
buf, err := os.Open(file)
|
2021-04-15 05:04:58 +00:00
|
|
|
|
2018-02-01 11:22:45 +00:00
|
|
|
if err != nil {
|
2021-04-15 05:04:58 +00:00
|
|
|
return err
|
2018-02-01 11:22:45 +00:00
|
|
|
}
|
2021-04-15 05:04:58 +00:00
|
|
|
|
|
|
|
err = r.parseServerListFile(buf)
|
|
|
|
|
2020-01-25 17:43:02 +00:00
|
|
|
buf.Close()
|
2021-04-15 05:04:58 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-02-01 11:22:45 +00:00
|
|
|
}
|
2021-04-15 05:04:58 +00:00
|
|
|
|
|
|
|
return nil
|
2018-02-01 11:22:45 +00:00
|
|
|
}
|
|
|
|
|
2015-02-12 09:19:46 +00:00
|
|
|
// Lookup will ask each nameserver in top-to-bottom fashion, starting a new request
|
|
|
|
// in every second, and return as early as possbile (have an answer).
|
|
|
|
// It returns an error if no request has succeeded.
|
2013-07-23 16:37:38 +00:00
|
|
|
func (r *Resolver) Lookup(net string, req *dns.Msg) (message *dns.Msg, err error) {
|
2020-01-25 17:43:02 +00:00
|
|
|
if net == "udp" && r.config.SetEDNS0 {
|
2017-02-14 17:08:08 +00:00
|
|
|
req = req.SetEdns0(65535, true)
|
|
|
|
}
|
|
|
|
|
2013-07-23 16:37:38 +00:00
|
|
|
qname := req.Question[0].Name
|
2013-07-23 11:10:38 +00:00
|
|
|
|
2018-02-01 10:30:41 +00:00
|
|
|
res := make(chan *RResp, 1)
|
2015-02-12 09:19:46 +00:00
|
|
|
var wg sync.WaitGroup
|
2021-04-15 03:42:24 +00:00
|
|
|
L := func(resolver *Resolver, nameserver *Nameserver) {
|
2015-02-12 09:19:46 +00:00
|
|
|
defer wg.Done()
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2018-07-02 00:47:22 +00:00
|
|
|
c, err := resolver.resolverFor(net, nameserver)
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2018-07-02 00:47:22 +00:00
|
|
|
if err != nil {
|
2021-04-15 05:04:58 +00:00
|
|
|
log.WithError(err).Warn("resolver failed to resolve")
|
2018-07-02 00:47:22 +00:00
|
|
|
return
|
2018-07-01 03:08:29 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 03:42:24 +00:00
|
|
|
r, rtt, err := c.Exchange(req, nameserver.address)
|
2018-07-02 00:47:22 +00:00
|
|
|
|
2013-07-23 16:37:38 +00:00
|
|
|
if err != nil {
|
2021-04-15 05:04:58 +00:00
|
|
|
log.WithFields(log.Fields{
|
|
|
|
"error": err,
|
|
|
|
"question": qname,
|
|
|
|
"nameserver": nameserver.address,
|
|
|
|
}).Warn("Socket error encountered")
|
2015-02-12 09:19:46 +00:00
|
|
|
return
|
2013-07-23 16:37:38 +00:00
|
|
|
}
|
2015-10-30 04:24:22 +00:00
|
|
|
// If SERVFAIL happen, should return immediately and try another upstream resolver.
|
|
|
|
// However, other Error code like NXDOMAIN is an clear response stating
|
|
|
|
// that it has been verified no such domain existas and ask other resolvers
|
|
|
|
// would make no sense. See more about #20
|
2013-07-23 16:37:38 +00:00
|
|
|
if r != nil && r.Rcode != dns.RcodeSuccess {
|
2021-04-15 05:04:58 +00:00
|
|
|
log.WithFields(log.Fields{
|
|
|
|
"question": qname,
|
|
|
|
"nameserver": nameserver.address,
|
|
|
|
}).Warn("Nameserver failed to get a valid answer")
|
|
|
|
|
2015-10-30 04:24:22 +00:00
|
|
|
if r.Rcode == dns.RcodeServerFailure {
|
|
|
|
return
|
|
|
|
}
|
2015-02-12 09:19:46 +00:00
|
|
|
}
|
2018-02-01 10:30:41 +00:00
|
|
|
re := &RResp{r, nameserver, rtt}
|
2015-02-12 09:19:46 +00:00
|
|
|
select {
|
2018-02-01 10:30:41 +00:00
|
|
|
case res <- re:
|
2015-02-12 09:19:46 +00:00
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-25 17:43:02 +00:00
|
|
|
ticker := time.NewTicker(time.Duration(r.config.Interval) * time.Millisecond)
|
2015-02-12 09:19:46 +00:00
|
|
|
defer ticker.Stop()
|
|
|
|
// Start lookup on each nameserver top-down, in every second
|
2018-02-01 07:39:47 +00:00
|
|
|
nameservers := r.Nameservers(qname)
|
|
|
|
for _, nameserver := range nameservers {
|
2015-02-12 09:19:46 +00:00
|
|
|
wg.Add(1)
|
2018-07-02 00:47:22 +00:00
|
|
|
go L(r, nameserver)
|
2015-02-12 09:19:46 +00:00
|
|
|
// but exit early, if we have an answer
|
|
|
|
select {
|
2018-02-01 10:30:41 +00:00
|
|
|
case re := <-res:
|
2021-04-15 05:04:58 +00:00
|
|
|
log.WithFields(log.Fields{
|
|
|
|
"question": utils.UnFqdn(qname),
|
|
|
|
"nameserver": re.nameserver.address,
|
|
|
|
"rtt": re.rtt,
|
|
|
|
}).Debug("Resolve")
|
2018-02-01 10:30:41 +00:00
|
|
|
return re.msg, nil
|
2015-02-12 09:19:46 +00:00
|
|
|
case <-ticker.C:
|
2013-07-23 16:37:38 +00:00
|
|
|
continue
|
|
|
|
}
|
2015-02-12 09:19:46 +00:00
|
|
|
}
|
|
|
|
// wait for all the namservers to finish
|
|
|
|
wg.Wait()
|
|
|
|
select {
|
2018-02-01 10:30:41 +00:00
|
|
|
case re := <-res:
|
2021-04-15 05:04:58 +00:00
|
|
|
log.WithFields(log.Fields{
|
|
|
|
"question": utils.UnFqdn(qname),
|
|
|
|
"nameserver": re.nameserver.address,
|
|
|
|
"rtt": re.rtt,
|
|
|
|
}).Debug("Resolve")
|
2018-02-01 10:30:41 +00:00
|
|
|
return re.msg, nil
|
2015-02-12 09:19:46 +00:00
|
|
|
default:
|
2018-02-01 07:39:47 +00:00
|
|
|
return nil, ResolvError{qname, net, nameservers}
|
2013-07-23 11:10:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-15 03:42:24 +00:00
|
|
|
func (r *Resolver) resolverFor(network string, n *Nameserver) (*dns.Client, error) {
|
|
|
|
key := network
|
2020-02-08 03:38:22 +00:00
|
|
|
|
2021-04-15 03:42:24 +00:00
|
|
|
// Use HTTPS if network is https, or TLS to force secure connections
|
|
|
|
if n.net == "https" {
|
|
|
|
key = n.net
|
|
|
|
} else if n.net == "tcp-tls" {
|
|
|
|
key = n.net + ":" + n.address
|
2020-02-08 03:38:22 +00:00
|
|
|
}
|
|
|
|
|
2020-01-25 17:43:02 +00:00
|
|
|
r.clientLock.RLock()
|
2020-02-08 03:38:22 +00:00
|
|
|
client, exists := r.clients[key]
|
2020-01-25 17:43:02 +00:00
|
|
|
r.clientLock.RUnlock()
|
|
|
|
|
|
|
|
if exists {
|
|
|
|
return client, nil
|
|
|
|
}
|
|
|
|
|
2021-04-15 03:42:24 +00:00
|
|
|
if n.net != "tcp" && n.net != "tcp-tls" && n.net != "https" && n.net != "udp" {
|
2020-01-25 17:43:02 +00:00
|
|
|
return nil, errors.New("unknown network type")
|
|
|
|
}
|
|
|
|
|
|
|
|
timeout := r.Timeout()
|
|
|
|
|
|
|
|
client = &dns.Client{
|
2021-04-15 03:42:24 +00:00
|
|
|
Net: n.net,
|
2020-01-25 17:43:02 +00:00
|
|
|
ReadTimeout: timeout,
|
|
|
|
WriteTimeout: timeout,
|
2018-07-02 00:47:22 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 03:42:24 +00:00
|
|
|
if n.net == "tcp-tls" {
|
2021-04-15 05:04:58 +00:00
|
|
|
host := n.host
|
2020-01-25 17:43:02 +00:00
|
|
|
|
2021-04-15 05:04:58 +00:00
|
|
|
if host == "" {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
host, _, err = net.SplitHostPort(n.address)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
host = n.address
|
|
|
|
}
|
2021-04-15 03:42:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
client.TLSConfig = &tls.Config{
|
|
|
|
ServerName: host,
|
2020-01-25 17:43:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r.clientLock.Lock()
|
2020-02-08 03:38:22 +00:00
|
|
|
r.clients[key] = client
|
2020-01-25 17:43:02 +00:00
|
|
|
r.clientLock.Lock()
|
|
|
|
|
|
|
|
return client, nil
|
2018-07-02 00:47:22 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 03:42:24 +00:00
|
|
|
// Nameservers return the array of nameservers, with port number appended.
|
2015-02-11 15:57:25 +00:00
|
|
|
// '#' in the name is treated as port separator, as with dnsmasq.
|
2015-02-03 14:53:57 +00:00
|
|
|
|
2021-04-15 03:42:24 +00:00
|
|
|
func (r *Resolver) Nameservers(qname string) []*Nameserver {
|
2015-02-03 14:53:57 +00:00
|
|
|
queryKeys := strings.Split(qname, ".")
|
|
|
|
queryKeys = queryKeys[:len(queryKeys)-1] // ignore last '.'
|
|
|
|
|
2021-04-15 03:42:24 +00:00
|
|
|
if v, found := r.domainServer.search(queryKeys); found {
|
2021-04-15 05:04:58 +00:00
|
|
|
log.WithFields(log.Fields{
|
|
|
|
"question": qname,
|
|
|
|
"upstream": v.address,
|
|
|
|
}).Debug("Found in domain server list")
|
2018-07-01 22:44:11 +00:00
|
|
|
|
2018-02-01 10:30:41 +00:00
|
|
|
//Ensure query the specific upstream nameserver in async Lookup() function.
|
2021-04-15 05:04:58 +00:00
|
|
|
return []*Nameserver{v}
|
2013-07-23 11:10:38 +00:00
|
|
|
}
|
2018-07-01 03:08:29 +00:00
|
|
|
|
2021-04-15 03:42:24 +00:00
|
|
|
return r.servers
|
2013-07-23 11:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Resolver) Timeout() time.Duration {
|
|
|
|
return time.Duration(r.config.Timeout) * time.Second
|
|
|
|
}
|
2021-04-15 05:04:58 +00:00
|
|
|
|
|
|
|
func determineNet(t, server string) string {
|
|
|
|
if t != "" {
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasPrefix(server, "https") {
|
|
|
|
return "https"
|
|
|
|
}
|
|
|
|
|
|
|
|
return "udp"
|
|
|
|
}
|