mirror of
https://github.com/DNSCrypt/dnscrypt-proxy.git
synced 2024-09-21 09:57:17 +03:00
Use a fallback resolver if the local DNS configuration doesn't work
This should fix all chicken-and-egg issues
This commit is contained in:
parent
24c21d5eb2
commit
ecaf18f614
@ -41,6 +41,7 @@ type Config struct {
|
||||
SourceIPv4 bool `toml:"ipv4_servers"`
|
||||
SourceIPv6 bool `toml:"ipv6_servers"`
|
||||
MaxClients uint32 `toml:"max_clients"`
|
||||
FallbackResolver string `toml:"fallback_resolver"`
|
||||
}
|
||||
|
||||
func newConfig() Config {
|
||||
@ -59,6 +60,7 @@ func newConfig() Config {
|
||||
SourceIPv4: true,
|
||||
SourceIPv6: false,
|
||||
MaxClients: 100,
|
||||
FallbackResolver: DefaultFallbackResolver,
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,6 +131,7 @@ func ConfigLoad(proxy *Proxy, svcFlag *string, config_file string) error {
|
||||
} else if config.LogFile != nil {
|
||||
dlog.UseLogFile(*config.LogFile)
|
||||
}
|
||||
proxy.xTransport.fallbackResolver = config.FallbackResolver
|
||||
proxy.timeout = time.Duration(config.Timeout) * time.Millisecond
|
||||
proxy.maxClients = config.MaxClients
|
||||
proxy.mainProto = "udp"
|
||||
@ -223,7 +226,7 @@ func ConfigLoad(proxy *Proxy, svcFlag *string, config_file string) error {
|
||||
if cfgSource.RefreshDelay <= 0 {
|
||||
cfgSource.RefreshDelay = 24
|
||||
}
|
||||
source, sourceUrlsToPrefetch, err := NewSource(cfgSource.URL, cfgSource.MinisignKeyStr, cfgSource.CacheFile, cfgSource.FormatStr, time.Duration(cfgSource.RefreshDelay)*time.Hour)
|
||||
source, sourceUrlsToPrefetch, err := NewSource(proxy.xTransport, cfgSource.URL, cfgSource.MinisignKeyStr, cfgSource.CacheFile, cfgSource.FormatStr, time.Duration(cfgSource.RefreshDelay)*time.Hour)
|
||||
proxy.urlsToPrefetch = append(proxy.urlsToPrefetch, sourceUrlsToPrefetch...)
|
||||
if err != nil {
|
||||
dlog.Criticalf("Unable use source [%s]: [%s]", cfgSourceName, err)
|
||||
|
@ -15,7 +15,6 @@
|
||||
## If this line is commented, all registered servers will be used
|
||||
|
||||
# server_names = ['scaleway-fr', 'google', 'yandex']
|
||||
server_names =['google']
|
||||
|
||||
## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6.
|
||||
## To only use systemd activation sockets, use an empty set: []
|
||||
@ -65,17 +64,17 @@ force_tcp = false
|
||||
timeout = 2500
|
||||
|
||||
|
||||
# Log level (0-6, default: 2 - 0 is very verbose, 6 only contains fatal errors)
|
||||
## Log level (0-6, default: 2 - 0 is very verbose, 6 only contains fatal errors)
|
||||
|
||||
# log_level = 2
|
||||
|
||||
|
||||
# log file for the application
|
||||
## log file for the application
|
||||
|
||||
# log_file = 'dnscrypt-proxy.log'
|
||||
|
||||
|
||||
# Use the system logger (syslog on Unix, Event Log on Windows)
|
||||
## Use the system logger (syslog on Unix, Event Log on Windows)
|
||||
|
||||
# use_syslog = true
|
||||
|
||||
@ -85,6 +84,18 @@ timeout = 2500
|
||||
cert_refresh_delay = 30
|
||||
|
||||
|
||||
## Fallback resolver
|
||||
## This is a normal, non-encrypted resolver, that will be only used
|
||||
## for one-shot queries when retrieving the initial resolvers list, and
|
||||
## only if the system DNS configuration doesn't work.
|
||||
## No user application queries will ever be leaked through this resolver,
|
||||
## and it will not be used after IP addresses of resolvers URLs have been found.
|
||||
## It will never be used at all if lists have already been cached, and if
|
||||
## stamps don't include host names without IP addresses.
|
||||
## A resolver supporting DNSSEC is recommended. This may become mandatory.
|
||||
|
||||
fallback_resolver = "9.9.9.9:53"
|
||||
|
||||
|
||||
#########################
|
||||
# Filters #
|
||||
|
@ -6,6 +6,7 @@
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jedisct1/dlog"
|
||||
"github.com/kardianos/service"
|
||||
@ -40,12 +41,12 @@ func main() {
|
||||
dlog.Debug(err)
|
||||
}
|
||||
app.proxy = Proxy{}
|
||||
app.proxy.xTransport = NewXTransport(30 * time.Second)
|
||||
|
||||
cdFileDir(ConfigFileName)
|
||||
if err := ConfigLoad(&app.proxy, svcFlag, ConfigFileName); err != nil {
|
||||
dlog.Fatal(err)
|
||||
}
|
||||
app.proxy.xTransport = NewXTransport(app.proxy.timeout)
|
||||
dlog.Noticef("Starting dnscrypt-proxy %s", AppVersion)
|
||||
|
||||
if len(*svcFlag) != 0 {
|
||||
|
@ -1,11 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@ -108,8 +106,8 @@ func (proxy *Proxy) prefetcher(urlsToPrefetch *[]URLToPrefetch) {
|
||||
urlToPrefetch := &(*urlsToPrefetch)[i]
|
||||
if now.After(urlToPrefetch.when) {
|
||||
dlog.Debugf("Prefetching [%s]", urlToPrefetch.url)
|
||||
if err := PrefetchSourceURL(urlToPrefetch); err != nil {
|
||||
dlog.Debugf("Prefetching [%s] failed: %s", err)
|
||||
if err := PrefetchSourceURL(proxy.xTransport, urlToPrefetch); err != nil {
|
||||
dlog.Debugf("Prefetching [%s] failed: %s", urlToPrefetch.url, err)
|
||||
} else {
|
||||
dlog.Debugf("Prefetching [%s] succeeded. Next refresh scheduled for %v", urlToPrefetch.url, urlToPrefetch.when)
|
||||
}
|
||||
@ -278,25 +276,8 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, clientProto str
|
||||
return
|
||||
}
|
||||
} else if serverInfo.Proto == StampProtoTypeDoH {
|
||||
req := &http.Request{
|
||||
Method: "POST",
|
||||
URL: serverInfo.URL,
|
||||
Host: serverInfo.HostName,
|
||||
Header: map[string][]string{
|
||||
"Accept": {"application/dns-udpwireformat"},
|
||||
"Content-Type": {"application/dns-udpwireformat"},
|
||||
"User-Agent": {"dnscrypt-proxy"},
|
||||
},
|
||||
Close: false,
|
||||
Body: ioutil.NopCloser(bytes.NewReader(query)),
|
||||
}
|
||||
client := http.Client{
|
||||
Transport: proxy.xTransport.transport,
|
||||
Timeout: proxy.timeout,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if (err == nil && resp != nil && (resp.StatusCode < 200 || resp.StatusCode > 299)) ||
|
||||
err != nil || resp == nil {
|
||||
resp, _, err := proxy.xTransport.Post(serverInfo.URL, "application/dns-udpwireformat", "application/dns-udpwireformat", query, proxy.timeout)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
response, err = ioutil.ReadAll(resp.Body)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
@ -9,7 +8,6 @@
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -209,46 +207,16 @@ func (serversInfo *ServersInfo) fetchDoHServerInfo(proxy *Proxy, name string, st
|
||||
Host: stamp.providerName,
|
||||
Path: stamp.path,
|
||||
}
|
||||
client := http.Client{
|
||||
Transport: proxy.xTransport.transport,
|
||||
Timeout: proxy.timeout,
|
||||
}
|
||||
preReq := &http.Request{
|
||||
Method: "HEAD",
|
||||
URL: url,
|
||||
Header: map[string][]string{
|
||||
"User-Agent": {"dnscrypt-proxy"},
|
||||
},
|
||||
Close: false,
|
||||
Host: stamp.providerName,
|
||||
}
|
||||
if _, err := client.Do(preReq); err != nil {
|
||||
return ServerInfo{}, err
|
||||
}
|
||||
body := ioutil.NopCloser(bytes.NewReader([]byte{
|
||||
body := []byte{
|
||||
0xca, 0xfe, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
}))
|
||||
req := &http.Request{
|
||||
Method: "POST",
|
||||
URL: url,
|
||||
Header: map[string][]string{
|
||||
"Accept": {"application/dns-udpwireformat"},
|
||||
"Content-Type": {"application/dns-udpwireformat"},
|
||||
"User-Agent": {"dnscrypt-proxy"},
|
||||
},
|
||||
Close: false,
|
||||
Host: stamp.providerName,
|
||||
Body: body,
|
||||
}
|
||||
start := time.Now()
|
||||
resp, err := client.Do(req)
|
||||
rtt := time.Since(start)
|
||||
if err == nil && resp != nil && (resp.StatusCode < 200 || resp.StatusCode > 299) {
|
||||
return ServerInfo{}, fmt.Errorf("Webserver returned code %d", resp.StatusCode)
|
||||
} else if err != nil {
|
||||
_, _, err := proxy.xTransport.Post(url, "application/dns-udpwireformat", "application/dns-udpwireformat", body, proxy.timeout)
|
||||
if err != nil {
|
||||
return ServerInfo{}, err
|
||||
}
|
||||
resp, rtt, err := proxy.xTransport.Post(url, "application/dns-udpwireformat", "application/dns-udpwireformat", body, proxy.timeout)
|
||||
if err != nil {
|
||||
return ServerInfo{}, err
|
||||
} else if resp == nil {
|
||||
return ServerInfo{}, errors.New("Webserver returned an error")
|
||||
}
|
||||
tls := resp.TLS
|
||||
if tls == nil || !tls.HandshakeComplete {
|
||||
|
@ -6,6 +6,7 @@
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@ -58,7 +59,7 @@ func fetchFromCache(cacheFile string) (in string, delayTillNextUpdate time.Durat
|
||||
return
|
||||
}
|
||||
|
||||
func fetchWithCache(url string, cacheFile string) (in string, cached bool, delayTillNextUpdate time.Duration, err error) {
|
||||
func fetchWithCache(xTransport *XTransport, urlStr string, cacheFile string) (in string, cached bool, delayTillNextUpdate time.Duration, err error) {
|
||||
cached = false
|
||||
in, delayTillNextUpdate, err = fetchFromCache(cacheFile)
|
||||
if err == nil {
|
||||
@ -67,8 +68,13 @@ func fetchWithCache(url string, cacheFile string) (in string, cached bool, delay
|
||||
return
|
||||
}
|
||||
var resp *http.Response
|
||||
dlog.Infof("Loading source information from URL [%s]", url)
|
||||
resp, err = http.Get(url)
|
||||
dlog.Infof("Loading source information from URL [%s]", urlStr)
|
||||
|
||||
url, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp, _, err = xTransport.Get(url, 30*time.Second)
|
||||
if err == nil && resp != nil && (resp.StatusCode < 200 || resp.StatusCode > 299) {
|
||||
err = fmt.Errorf("Webserver returned code %d", resp.StatusCode)
|
||||
return
|
||||
@ -100,7 +106,7 @@ type URLToPrefetch struct {
|
||||
when time.Time
|
||||
}
|
||||
|
||||
func NewSource(url string, minisignKeyStr string, cacheFile string, formatStr string, refreshDelay time.Duration) (Source, []URLToPrefetch, error) {
|
||||
func NewSource(xTransport *XTransport, url string, minisignKeyStr string, cacheFile string, formatStr string, refreshDelay time.Duration) (Source, []URLToPrefetch, error) {
|
||||
_ = refreshDelay
|
||||
source := Source{url: url}
|
||||
if formatStr == "v1" {
|
||||
@ -118,11 +124,11 @@ func NewSource(url string, minisignKeyStr string, cacheFile string, formatStr st
|
||||
urlsToPrefetch := []URLToPrefetch{}
|
||||
|
||||
sigURL := url + ".minisig"
|
||||
in, cached, delayTillNextUpdate, err := fetchWithCache(url, cacheFile)
|
||||
in, cached, delayTillNextUpdate, err := fetchWithCache(xTransport, url, cacheFile)
|
||||
urlsToPrefetch = append(urlsToPrefetch, URLToPrefetch{url: url, cacheFile: cacheFile, when: now.Add(delayTillNextUpdate)})
|
||||
|
||||
sigCacheFile := cacheFile + ".minisig"
|
||||
sigStr, sigCached, sigDelayTillNextUpdate, sigErr := fetchWithCache(sigURL, sigCacheFile)
|
||||
sigStr, sigCached, sigDelayTillNextUpdate, sigErr := fetchWithCache(xTransport, sigURL, sigCacheFile)
|
||||
urlsToPrefetch = append(urlsToPrefetch, URLToPrefetch{url: sigURL, cacheFile: sigCacheFile, when: now.Add(sigDelayTillNextUpdate)})
|
||||
|
||||
if err != nil || sigErr != nil {
|
||||
@ -253,8 +259,8 @@ func (source *Source) parseV2(prefix string) ([]RegisteredServer, error) {
|
||||
return registeredServers, nil
|
||||
}
|
||||
|
||||
func PrefetchSourceURL(urlToPrefetch *URLToPrefetch) error {
|
||||
in, _, delayTillNextUpdate, err := fetchWithCache(urlToPrefetch.url, urlToPrefetch.cacheFile)
|
||||
func PrefetchSourceURL(xTransport *XTransport, urlToPrefetch *URLToPrefetch) error {
|
||||
in, _, delayTillNextUpdate, err := fetchWithCache(xTransport, urlToPrefetch.url, urlToPrefetch.cacheFile)
|
||||
if err == nil {
|
||||
AtomicFileWrite(urlToPrefetch.cacheFile, []byte(in))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user