Add support for DNS stamps and for DNSCrypt servers

This allows connections to DoH servers using their stamp, and adds
support for DNSCrypt servers by the way.
This commit is contained in:
Frank Denis 2021-04-24 17:27:43 +02:00 committed by Karan Sharma
parent 48fd5bb792
commit 6d2eae4f58
9 changed files with 139 additions and 12 deletions

View file

@ -8,11 +8,12 @@ const (
// DefaultUDPPort specifies the default port for a DNS server connecting over UDP
DefaultUDPPort = "53"
// DefaultTCPPort specifies the default port for a DNS server connecting over TCP
DefaultTCPPort = "53"
UDPResolver = "udp"
DOHResolver = "doh"
TCPResolver = "tcp"
DOTResolver = "dot"
DefaultTCPPort = "53"
UDPResolver = "udp"
DOHResolver = "doh"
TCPResolver = "tcp"
DOTResolver = "dot"
DNSCryptResolver = "dnscrypt"
)
// QueryFlags is used store the query params

81
pkg/resolvers/dnscrypt.go Normal file
View file

@ -0,0 +1,81 @@
package resolvers
import (
"github.com/ameshkov/dnscrypt"
"github.com/miekg/dns"
"github.com/sirupsen/logrus"
)
// DNSCryptResolver represents the config options for setting up a Resolver.
type DNSCryptResolver struct {
client *dnscrypt.Client
serverInfo *dnscrypt.ServerInfo
server string
resolverOptions Options
}
// DNSCryptResolverOpts holds options for setting up a DNSCrypt resolver.
type DNSCryptResolverOpts struct {
IPv4Only bool
IPv6Only bool
UseTLS bool
UseTCP bool
}
// NewDNSCryptResolver accepts a list of nameservers and configures a DNS resolver.
func NewDNSCryptResolver(server string, dnscryptOpts DNSCryptResolverOpts, resolverOpts Options) (Resolver, error) {
net := "udp"
if dnscryptOpts.UseTCP {
net = "tcp"
}
client := &dnscrypt.Client{Proto: net, AdjustPayloadSize: true}
serverInfo, _, err := client.Dial(server)
if err != nil {
return nil, err
}
return &DNSCryptResolver{
client: client,
serverInfo: serverInfo,
server: server,
resolverOptions: resolverOpts,
}, nil
}
// Lookup takes a dns.Question and sends them to DNS Server.
// It parses the Response from the server in a custom output format.
func (r *DNSCryptResolver) Lookup(question dns.Question) (Response, error) {
var (
rsp Response
messages = prepareMessages(question, r.resolverOptions.Ndots, r.resolverOptions.SearchList)
)
for _, msg := range messages {
r.resolverOptions.Logger.WithFields(logrus.Fields{
"domain": msg.Question[0].Name,
"ndots": r.resolverOptions.Ndots,
"nameserver": r.serverInfo.ProviderName,
}).Debug("Attempting to resolve")
in, rtt, err := r.client.Exchange(&msg, r.serverInfo)
if err != nil {
return rsp, err
}
// pack questions in output.
for _, q := range msg.Question {
ques := Question{
Name: q.Name,
Class: dns.ClassToString[q.Qclass],
Type: dns.TypeToString[q.Qtype],
}
rsp.Questions = append(rsp.Questions, ques)
}
// get the authorities and answers.
output := parseMessage(in, rtt, r.server)
rsp.Authorities = output.Authorities
rsp.Answers = output.Answers
if len(output.Answers) > 0 {
// stop iterating the searchlist.
break
}
}
return rsp, nil
}

View file

@ -127,6 +127,17 @@ func LoadResolvers(opts Options) ([]Resolver, error) {
}
rslvrs = append(rslvrs, rslvr)
}
if ns.Type == models.DNSCryptResolver {
opts.Logger.Debug("initiating DNSCrypt resolver")
rslvr, err := NewDNSCryptResolver(ns.Address,
DNSCryptResolverOpts{
UseTCP: false,
}, resolverOpts)
if err != nil {
return rslvrs, err
}
rslvrs = append(rslvrs, rslvr)
}
}
return rslvrs, nil
}