From 8b096af04e522f5e121c00567e1db9d1fdddc5b4 Mon Sep 17 00:00:00 2001 From: Quentin McGaw Date: Sat, 11 Jul 2020 23:51:53 +0000 Subject: [PATCH] DNS_KEEP_NAMESERVER variable, refers to #188 --- Dockerfile | 1 + README.md | 1 + internal/dns/dns.go | 2 +- internal/dns/loop.go | 8 ++++---- internal/dns/nameserver.go | 12 +++++++----- internal/dns/nameserver_test.go | 2 +- internal/params/dns.go | 6 ++++++ internal/params/params.go | 1 + internal/settings/dns.go | 10 ++++++++++ 9 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index 58de532e..8e6df432 100644 --- a/Dockerfile +++ b/Dockerfile @@ -76,6 +76,7 @@ ENV VPNSP=pia \ UNBLOCK= \ DNS_UPDATE_PERIOD=24h \ DNS_PLAINTEXT_ADDRESS=1.1.1.1 \ + DNS_KEEP_NAMESERVER=off \ # Firewall FIREWALL=on \ EXTRA_SUBNETS= \ diff --git a/README.md b/README.md index 568f67d2..514c0e18 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,7 @@ None of the following values are required. | `BLOCK_ADS` | `off` | `on`, `off` | Block ads hostnames and IPs with Unbound | | `UNBLOCK` | |i.e. `domain1.com,x.domain2.co.uk` | Comma separated list of domain names to leave unblocked with Unbound | | `DNS_PLAINTEXT_ADDRESS` | `1.1.1.1` | Any IP address | IP address to use as DNS resolver if `DOT` is `off` | +| `DNS_KEEP_NAMESERVER` | `off` | `on` or `off` | Keep the nameservers in /etc/resolv.conf untouched, but disabled DNS blocking features | ### Firewall diff --git a/internal/dns/dns.go b/internal/dns/dns.go index b30648f1..e76afc83 100644 --- a/internal/dns/dns.go +++ b/internal/dns/dns.go @@ -17,7 +17,7 @@ type Configurator interface { DownloadRootKey(uid, gid int) error MakeUnboundConf(settings settings.DNS, uid, gid int) (err error) UseDNSInternally(IP net.IP) - UseDNSSystemWide(IP net.IP) error + UseDNSSystemWide(ip net.IP, keepNameserver bool) error Start(ctx context.Context, logLevel uint8) (stdout io.ReadCloser, waitFn func() error, err error) WaitForUnbound() (err error) Version(ctx context.Context) (version string, err error) diff --git a/internal/dns/loop.go b/internal/dns/loop.go index f0a2a239..9b8d3055 100644 --- a/internal/dns/loop.go +++ b/internal/dns/loop.go @@ -104,8 +104,8 @@ func (l *looper) Run(ctx context.Context, restart <-chan struct{}, wg *sync.Wait // Started successfully go l.streamMerger.Merge(unboundCtx, stream, command.MergeName("unbound"), command.MergeColor(constants.ColorUnbound())) - l.conf.UseDNSInternally(net.IP{127, 0, 0, 1}) // use Unbound - if err := l.conf.UseDNSSystemWide(net.IP{127, 0, 0, 1}); err != nil { // use Unbound + l.conf.UseDNSInternally(net.IP{127, 0, 0, 1}) // use Unbound + if err := l.conf.UseDNSSystemWide(net.IP{127, 0, 0, 1}, l.settings.KeepNameserver); err != nil { // use Unbound l.logger.Error(err) } if err := l.conf.WaitForUnbound(); err != nil { @@ -148,7 +148,7 @@ func (l *looper) fallbackToUnencryptedDNS() { if targetIP != nil { l.logger.Info("falling back on plaintext DNS at address %s", targetIP) l.conf.UseDNSInternally(targetIP) - if err := l.conf.UseDNSSystemWide(targetIP); err != nil { + if err := l.conf.UseDNSSystemWide(targetIP, l.settings.KeepNameserver); err != nil { l.logger.Error(err) } return @@ -161,7 +161,7 @@ func (l *looper) fallbackToUnencryptedDNS() { if targetIP.To4() != nil { l.logger.Info("falling back on plaintext DNS at address %s", targetIP) l.conf.UseDNSInternally(targetIP) - if err := l.conf.UseDNSSystemWide(targetIP); err != nil { + if err := l.conf.UseDNSSystemWide(targetIP, l.settings.KeepNameserver); err != nil { l.logger.Error(err) } return diff --git a/internal/dns/nameserver.go b/internal/dns/nameserver.go index 79b32495..4fc30581 100644 --- a/internal/dns/nameserver.go +++ b/internal/dns/nameserver.go @@ -21,7 +21,7 @@ func (c *configurator) UseDNSInternally(ip net.IP) { } // UseDNSSystemWide changes the nameserver to use for DNS system wide -func (c *configurator) UseDNSSystemWide(ip net.IP) error { +func (c *configurator) UseDNSSystemWide(ip net.IP, keepNameserver bool) error { c.logger.Info("using DNS address %s system wide", ip.String()) data, err := c.fileManager.ReadFile(string(constants.ResolvConf)) if err != nil { @@ -33,10 +33,12 @@ func (c *configurator) UseDNSSystemWide(ip net.IP) error { lines = nil } found := false - for i := range lines { - if strings.HasPrefix(lines[i], "nameserver ") { - lines[i] = "nameserver " + ip.String() - found = true + if !keepNameserver { // default + for i := range lines { + if strings.HasPrefix(lines[i], "nameserver ") { + lines[i] = "nameserver " + ip.String() + found = true + } } } if !found { diff --git a/internal/dns/nameserver_test.go b/internal/dns/nameserver_test.go index 201146a1..d17ed4c7 100644 --- a/internal/dns/nameserver_test.go +++ b/internal/dns/nameserver_test.go @@ -62,7 +62,7 @@ func Test_UseDNSSystemWide(t *testing.T) { fileManager: fileManager, logger: logger, } - err := c.UseDNSSystemWide(net.IP{127, 0, 0, 1}) + err := c.UseDNSSystemWide(net.IP{127, 0, 0, 1}, false) if tc.err != nil { require.Error(t, err) assert.Equal(t, tc.err.Error(), err.Error()) diff --git a/internal/params/dns.go b/internal/params/dns.go index e20ab9b7..653d1259 100644 --- a/internal/params/dns.go +++ b/internal/params/dns.go @@ -157,3 +157,9 @@ func (r *reader) GetDNSPlaintext() (ip net.IP, err error) { } return ip, nil } + +// GetDNSKeepNameserver obtains if the nameserver present in /etc/resolv.conf +// should be kept instead of overridden, from the environment variable DNS_KEEP_NAMESERVER +func (r *reader) GetDNSKeepNameserver() (on bool, err error) { + return r.envParams.GetOnOff("DNS_KEEP_NAMESERVER", libparams.Default("off")) +} diff --git a/internal/params/params.go b/internal/params/params.go index e72d6fdc..7dccc6ad 100644 --- a/internal/params/params.go +++ b/internal/params/params.go @@ -30,6 +30,7 @@ type Reader interface { GetDNSOverTLSIPv6() (ipv6 bool, err error) GetDNSUpdatePeriod() (period time.Duration, err error) GetDNSPlaintext() (ip net.IP, err error) + GetDNSKeepNameserver() (on bool, err error) // System GetUID() (uid int, err error) diff --git a/internal/settings/dns.go b/internal/settings/dns.go index 73d3c77d..9dd6c1ff 100644 --- a/internal/settings/dns.go +++ b/internal/settings/dns.go @@ -14,6 +14,7 @@ import ( // DNS contains settings to configure Unbound for DNS over TLS operation type DNS struct { Enabled bool + KeepNameserver bool Providers []models.DNSProvider PlaintextAddress net.IP AllowedHostnames []string @@ -61,6 +62,10 @@ func (d *DNS) String() string { if d.UpdatePeriod > 0 { update = fmt.Sprintf("every %s", d.UpdatePeriod) } + keepNameserver := "no" + if d.KeepNameserver { + keepNameserver = "yes" + } settingsList := []string{ "DNS over TLS settings:", "DNS over TLS provider:\n |--" + strings.Join(providersStr, "\n |--"), @@ -75,6 +80,7 @@ func (d *DNS) String() string { "Validation log level: " + fmt.Sprintf("%d/2", d.ValidationLogLevel), "IPv6 resolution: " + ipv6, "Update: " + update, + "Keep nameserver (disabled blocking): " + keepNameserver, } return strings.Join(settingsList, "\n |--") } @@ -137,6 +143,10 @@ func GetDNSSettings(paramsReader params.Reader) (settings DNS, err error) { if err != nil { return settings, err } + settings.KeepNameserver, err = paramsReader.GetDNSKeepNameserver() + if err != nil { + return settings, err + } // Consistency check IPv6Support := false