Add an option to always ignore the system resolver

This makes startup faster when DoH resolvers without a static IP
are used (Google).
This commit is contained in:
Frank Denis 2018-01-30 17:37:35 +01:00
parent 931916097e
commit 1d35e249c9
3 changed files with 57 additions and 36 deletions

View File

@ -42,6 +42,7 @@ type Config struct {
SourceIPv6 bool `toml:"ipv6_servers"`
MaxClients uint32 `toml:"max_clients"`
FallbackResolver string `toml:"fallback_resolver"`
IgnoreSystemDNS bool `toml:"ignore_system_dns"`
}
func newConfig() Config {
@ -61,6 +62,7 @@ func newConfig() Config {
SourceIPv6: false,
MaxClients: 100,
FallbackResolver: DefaultFallbackResolver,
IgnoreSystemDNS: false,
}
}
@ -132,6 +134,9 @@ func ConfigLoad(proxy *Proxy, svcFlag *string, config_file string) error {
dlog.UseLogFile(*config.LogFile)
}
proxy.xTransport.fallbackResolver = config.FallbackResolver
if len(config.FallbackResolver) > 0 {
proxy.xTransport.ignoreSystemDNS = config.IgnoreSystemDNS
}
proxy.timeout = time.Duration(config.Timeout) * time.Millisecond
proxy.maxClients = config.MaxClients
proxy.mainProto = "udp"

View File

@ -14,7 +14,7 @@
## List of servers to use
## If this line is commented, all registered servers will be used
# server_names = ['scaleway-fr', 'google', 'yandex']
#server_names = ['scaleway-fr', 'google', 'yandex']
## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6.
@ -93,6 +93,11 @@ cert_refresh_delay = 30
fallback_resolver = "9.9.9.9:53"
## Never try to use the system DNS settings; unconditionally use the
## fallback resolver.
ignore_system_dns = false
#########################
# Filters #

View File

@ -30,6 +30,7 @@ type XTransport struct {
timeout time.Duration
cachedIPs CachedIPs
fallbackResolver string
ignoreSystemDNS bool
}
func NewXTransport(timeout time.Duration) *XTransport {
@ -37,6 +38,7 @@ func NewXTransport(timeout time.Duration) *XTransport {
cachedIPs: CachedIPs{cache: make(map[string]string)},
timeout: timeout,
fallbackResolver: DefaultFallbackResolver,
ignoreSystemDNS: false,
}
dialer := &net.Dialer{Timeout: timeout, KeepAlive: timeout, DualStack: true}
transport := &http.Transport{
@ -87,6 +89,49 @@ func (xTransport *XTransport) Fetch(method string, url *url.URL, accept string,
if body != nil {
req.Body = *body
}
var err error
host := url.Host
xTransport.cachedIPs.RLock()
cachedIP := xTransport.cachedIPs.cache[host]
xTransport.cachedIPs.RUnlock()
if !xTransport.ignoreSystemDNS || len(cachedIP) > 0 {
start := time.Now()
resp, err := client.Do(req)
rtt := time.Since(start)
if err == nil {
if resp == nil {
err = errors.New("Webserver returned an error")
} else if resp.StatusCode < 200 || resp.StatusCode > 299 {
err = fmt.Errorf("Webserver returned code %d", resp.StatusCode)
}
return resp, rtt, err
}
dlog.Debugf("[%s]: [%s]", req.URL, err)
} else {
dlog.Debug("Ignoring system DNS")
}
if len(cachedIP) > 0 && err != nil {
dlog.Debugf("IP for [%s] was cached to [%s], but connection failed: [%s]", host, cachedIP, err)
return nil, 0, err
}
dnsClient := new(dns.Client)
msg := new(dns.Msg)
msg.SetQuestion(dns.Fqdn(host), dns.TypeA)
msg.SetEdns0(4096, true)
dlog.Noticef("System DNS configuration not usable yet, exceptionally resolving [%s] using fallback resolver [%s]", host, xTransport.fallbackResolver)
in, _, err := dnsClient.Exchange(msg, xTransport.fallbackResolver)
if err != nil {
return nil, 0, err
}
if len(in.Answer) <= 0 {
return nil, 0, fmt.Errorf("No IP found for [%s]", host)
}
foundIP := in.Answer[0].(*dns.A).A.String()
xTransport.cachedIPs.Lock()
xTransport.cachedIPs.cache[host] = foundIP
xTransport.cachedIPs.Unlock()
dlog.Debugf("[%s] IP address [%s] added to the cache", host, foundIP)
start := time.Now()
resp, err := client.Do(req)
rtt := time.Since(start)
@ -96,43 +141,9 @@ func (xTransport *XTransport) Fetch(method string, url *url.URL, accept string,
} else if resp.StatusCode < 200 || resp.StatusCode > 299 {
err = fmt.Errorf("Webserver returned code %d", resp.StatusCode)
}
return resp, rtt, err
}
host := url.Host
xTransport.cachedIPs.RLock()
cachedIP := xTransport.cachedIPs.cache[host]
xTransport.cachedIPs.RUnlock()
if len(cachedIP) > 0 {
dlog.Debugf("IP for [%s] was cached to [%s], but connection failed: [%s]", host, cachedIP, err)
return resp, rtt, err
}
dnsClient := new(dns.Client)
msg := new(dns.Msg)
msg.SetQuestion(dns.Fqdn(host), dns.TypeA)
msg.SetEdns0(4096, true)
dlog.Noticef("System DNS configuration not usable yet, exceptionally resolving [%s] using fallback resolver [%s]", host, xTransport.fallbackResolver)
in, _, err := dnsClient.Exchange(msg, xTransport.fallbackResolver)
if err != nil {
return resp, rtt, err
}
if len(in.Answer) <= 0 {
return resp, rtt, fmt.Errorf("No IP found for [%s]", host)
}
foundIP := in.Answer[0].(*dns.A).A.String()
xTransport.cachedIPs.Lock()
xTransport.cachedIPs.cache[host] = foundIP
xTransport.cachedIPs.Unlock()
dlog.Debugf("[%s] IP address [%s] added to the cache", host, foundIP)
start = time.Now()
resp, err = client.Do(req)
rtt = time.Since(start)
if err == nil {
if resp == nil {
err = errors.New("Webserver returned an error")
} else if resp.StatusCode < 200 || resp.StatusCode > 299 {
err = fmt.Errorf("Webserver returned code %d", resp.StatusCode)
}
dlog.Debugf("[%s]: [%s]", req.URL, err)
}
return resp, rtt, err
}