@@ -13,6 +13,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jedisct1/go-dnsstamps"
|
||||
|
||||
"github.com/ameshkov/dnscrypt"
|
||||
"github.com/joomcode/errorx"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@@ -177,6 +180,51 @@ func (p *dnsOverHTTPS) Exchange(m *dns.Msg) (*dns.Msg, error) {
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
//
|
||||
// DNSCrypt
|
||||
//
|
||||
type dnsCrypt struct {
|
||||
boot bootstrapper
|
||||
client *dnscrypt.Client // DNSCrypt client properties
|
||||
serverInfo *dnscrypt.ServerInfo // DNSCrypt server info
|
||||
|
||||
sync.RWMutex // protects DNSCrypt client
|
||||
}
|
||||
|
||||
func (p *dnsCrypt) Address() string { return p.boot.address }
|
||||
|
||||
func (p *dnsCrypt) Exchange(m *dns.Msg) (*dns.Msg, error) {
|
||||
|
||||
var client *dnscrypt.Client
|
||||
var serverInfo *dnscrypt.ServerInfo
|
||||
|
||||
p.RLock()
|
||||
client = p.client
|
||||
serverInfo = p.serverInfo
|
||||
p.RUnlock()
|
||||
|
||||
if client == nil || serverInfo == nil {
|
||||
p.Lock()
|
||||
|
||||
// Using "udp" for DNSCrypt upstreams by default
|
||||
client = &dnscrypt.Client{Proto: "udp", Timeout: defaultTimeout}
|
||||
si, _, err := client.Dial(p.boot.address)
|
||||
|
||||
if err != nil {
|
||||
p.Unlock()
|
||||
return nil, errorx.Decorate(err, "Failed to fetch certificate info from %s", p.Address())
|
||||
}
|
||||
|
||||
p.client = client
|
||||
p.serverInfo = si
|
||||
serverInfo = si
|
||||
p.Unlock()
|
||||
}
|
||||
|
||||
reply, _, err := client.Exchange(m, serverInfo)
|
||||
return reply, err
|
||||
}
|
||||
|
||||
func (s *Server) chooseUpstream() Upstream {
|
||||
upstreams := s.Upstreams
|
||||
if upstreams == nil {
|
||||
@@ -200,6 +248,20 @@ func AddressToUpstream(address string, bootstrap string) (Upstream, error) {
|
||||
return nil, errorx.Decorate(err, "Failed to parse %s", address)
|
||||
}
|
||||
switch url.Scheme {
|
||||
case "sdns":
|
||||
stamp, err := dnsstamps.NewServerStampFromString(address)
|
||||
if err != nil {
|
||||
return nil, errorx.Decorate(err, "Failed to parse %s", address)
|
||||
}
|
||||
|
||||
switch stamp.Proto {
|
||||
case dnsstamps.StampProtoTypeDNSCrypt:
|
||||
return &dnsCrypt{boot: toBoot(url.String(), bootstrap)}, nil
|
||||
case dnsstamps.StampProtoTypeDoH:
|
||||
return AddressToUpstream(fmt.Sprintf("https://%s%s", stamp.ProviderName, stamp.Path), bootstrap)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Unsupported protocol %v in %s", stamp.Proto, address)
|
||||
case "dns":
|
||||
if url.Port() == "" {
|
||||
url.Host += ":53"
|
||||
|
||||
Reference in New Issue
Block a user