mirror of
https://github.com/qdm12/gluetun.git
synced 2026-05-06 20:10:11 +02:00
chore(dns): remove DNS_SERVER, DNS_KEEP_NAMESERVER and replace DNS_ADDRESS with DNS_UPSTREAM_PLAIN_ADDRESSES (#2988)
- Remove `DNS_SERVER` (aka DOT) option: the DNS server forwarder part is now always enabled (see below why) - Remove `DNS_KEEP_NAMESERVER`: the container will always use the built-in DNS server forwarder, because it can handle now local names with local resolvers (see #2970), it can use the `plain` upstream type (see https://github.com/qdm12/gluetun/commit/5ed6e8292278b54bb5081de0e8ccd0d63a275b3c) AND you can use `DNS_UPSTREAM_PLAIN_ADDRESSES` (see below) - Replace `DNS_ADDRESS` with `DNS_UPSTREAM_PLAIN_ADDRESSES`: - New CSV format with port, for example `ip1:port1,ip2:port2` - requires `DNS_UPSTREAM_TYPE=plain` to be set to use `DNS_UPSTREAM_PLAIN_ADDRESSES` (unless using retro `DNS_ADDRESS`) - retrocompatibility with `DNS_ADDRESS`. If set, force upstream type to plain and empty user-picked providers. 127.0.0.1 is now ignored since it's always set to this value internally. - Warning log on using private upstream resolvers updated - Warning log if using a private IP address for the plain DNS server which is not in your local subnets All in all, this greatly simplifies code and available options (less options for the same features is a win). It also allows you to specify multiple plain DNS resolvers on ports other than 53 if needed.
This commit is contained in:
@@ -3,6 +3,8 @@ package dns
|
||||
type Logger interface {
|
||||
Debug(s string)
|
||||
Info(s string)
|
||||
Infof(format string, args ...any)
|
||||
Warn(s string)
|
||||
Warnf(format string, args ...any)
|
||||
Error(s string)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type Loop struct {
|
||||
server *server.Server
|
||||
filter *mapfilter.Filter
|
||||
localResolvers []netip.Addr
|
||||
localSubnets []netip.Prefix
|
||||
resolvConf string
|
||||
client *http.Client
|
||||
logger Logger
|
||||
@@ -39,7 +40,7 @@ type Loop struct {
|
||||
const defaultBackoffTime = 10 * time.Second
|
||||
|
||||
func NewLoop(settings settings.DNS,
|
||||
client *http.Client, logger Logger,
|
||||
client *http.Client, logger Logger, localSubnets []netip.Prefix,
|
||||
) (loop *Loop, err error) {
|
||||
start := make(chan struct{})
|
||||
running := make(chan models.LoopStatus)
|
||||
@@ -62,6 +63,7 @@ func NewLoop(settings settings.DNS,
|
||||
state: state,
|
||||
server: nil,
|
||||
filter: filter,
|
||||
localSubnets: localSubnets,
|
||||
resolvConf: "/etc/resolv.conf",
|
||||
client: client,
|
||||
logger: logger,
|
||||
|
||||
+11
-30
@@ -17,14 +17,8 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
|
||||
return
|
||||
}
|
||||
|
||||
if *l.GetSettings().KeepNameserver {
|
||||
l.logger.Warn("⚠️⚠️⚠️ keeping the default container nameservers, " +
|
||||
"this will likely leak DNS traffic outside the VPN " +
|
||||
"and go through your container network DNS outside the VPN tunnel!")
|
||||
} else {
|
||||
const fallback = false
|
||||
l.useUnencryptedDNS(fallback)
|
||||
}
|
||||
const fallback = false
|
||||
l.useUnencryptedDNS(fallback)
|
||||
|
||||
select {
|
||||
case <-l.start:
|
||||
@@ -37,13 +31,13 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
|
||||
// Their values are to be used if DOT=off
|
||||
var runError <-chan error
|
||||
|
||||
settings := l.GetSettings()
|
||||
for !*settings.KeepNameserver && *settings.ServerEnabled {
|
||||
for {
|
||||
settings := l.GetSettings()
|
||||
var err error
|
||||
runError, err = l.setupServer(ctx)
|
||||
runError, err = l.setupServer(ctx, settings)
|
||||
if err == nil {
|
||||
l.backoffTime = defaultBackoffTime
|
||||
l.logger.Info("ready and using DNS server at address " + settings.ServerAddress.String())
|
||||
l.logger.Infof("ready and using DNS server with %s upstream resolvers", settings.UpstreamType)
|
||||
|
||||
err = l.updateFiles(ctx, settings)
|
||||
if err != nil {
|
||||
@@ -58,16 +52,9 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
|
||||
return
|
||||
}
|
||||
l.logAndWait(ctx, err)
|
||||
settings = l.GetSettings()
|
||||
}
|
||||
l.signalOrSetStatus(constants.Running)
|
||||
|
||||
settings = l.GetSettings()
|
||||
if !*settings.KeepNameserver && !*settings.ServerEnabled {
|
||||
const fallback = false
|
||||
l.useUnencryptedDNS(fallback)
|
||||
}
|
||||
|
||||
l.userTrigger = false
|
||||
|
||||
exitLoop := l.runWait(ctx, runError)
|
||||
@@ -81,21 +68,15 @@ func (l *Loop) runWait(ctx context.Context, runError <-chan error) (exitLoop boo
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
settings := l.GetSettings()
|
||||
if !*settings.KeepNameserver && *settings.ServerEnabled {
|
||||
l.stopServer()
|
||||
// TODO revert OS and Go nameserver when exiting
|
||||
}
|
||||
l.stopServer()
|
||||
// TODO revert OS and Go nameserver when exiting
|
||||
return true
|
||||
case <-l.stop:
|
||||
l.userTrigger = true
|
||||
l.logger.Info("stopping")
|
||||
settings := l.GetSettings()
|
||||
if !*settings.KeepNameserver && *settings.ServerEnabled {
|
||||
const fallback = false
|
||||
l.useUnencryptedDNS(fallback)
|
||||
l.stopServer()
|
||||
}
|
||||
const fallback = false
|
||||
l.useUnencryptedDNS(fallback)
|
||||
l.stopServer()
|
||||
l.stopped <- struct{}{}
|
||||
case <-l.start:
|
||||
l.userTrigger = true
|
||||
|
||||
+54
-18
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"slices"
|
||||
|
||||
"github.com/qdm12/dns/v2/pkg/doh"
|
||||
"github.com/qdm12/dns/v2/pkg/dot"
|
||||
@@ -26,31 +27,23 @@ func (l *Loop) SetSettings(ctx context.Context, settings settings.DNS) (
|
||||
return l.state.SetSettings(ctx, settings)
|
||||
}
|
||||
|
||||
func buildServerSettings(settings settings.DNS,
|
||||
func buildServerSettings(userSettings settings.DNS,
|
||||
filter *mapfilter.Filter, localResolvers []netip.Addr,
|
||||
logger Logger) (
|
||||
localSubnets []netip.Prefix, logger Logger) (
|
||||
serverSettings server.Settings, err error,
|
||||
) {
|
||||
serverSettings.Logger = logger
|
||||
|
||||
providersData := provider.NewProviders()
|
||||
upstreamResolvers := make([]provider.Provider, len(settings.Providers))
|
||||
for i := range settings.Providers {
|
||||
var err error
|
||||
upstreamResolvers[i], err = providersData.Get(settings.Providers[i])
|
||||
if err != nil {
|
||||
panic(err) // this should already had been checked
|
||||
}
|
||||
}
|
||||
upstreamResolvers := buildProviders(userSettings, localSubnets, logger)
|
||||
|
||||
ipVersion := "ipv4"
|
||||
if *settings.IPv6 {
|
||||
if *userSettings.IPv6 {
|
||||
ipVersion = "ipv6"
|
||||
}
|
||||
|
||||
var dialer server.Dialer
|
||||
switch settings.UpstreamType {
|
||||
case "dot":
|
||||
switch userSettings.UpstreamType {
|
||||
case settings.DNSUpstreamTypeDot:
|
||||
dialerSettings := dot.Settings{
|
||||
UpstreamResolvers: upstreamResolvers,
|
||||
IPVersion: ipVersion,
|
||||
@@ -59,7 +52,7 @@ func buildServerSettings(settings settings.DNS,
|
||||
if err != nil {
|
||||
return server.Settings{}, fmt.Errorf("creating DNS over TLS dialer: %w", err)
|
||||
}
|
||||
case "doh":
|
||||
case settings.DNSUpstreamTypeDoh:
|
||||
dialerSettings := doh.Settings{
|
||||
UpstreamResolvers: upstreamResolvers,
|
||||
IPVersion: ipVersion,
|
||||
@@ -68,7 +61,7 @@ func buildServerSettings(settings settings.DNS,
|
||||
if err != nil {
|
||||
return server.Settings{}, fmt.Errorf("creating DNS over HTTPS dialer: %w", err)
|
||||
}
|
||||
case "plain":
|
||||
case settings.DNSUpstreamTypePlain:
|
||||
dialerSettings := plain.Settings{
|
||||
UpstreamResolvers: upstreamResolvers,
|
||||
IPVersion: ipVersion,
|
||||
@@ -78,11 +71,11 @@ func buildServerSettings(settings settings.DNS,
|
||||
return server.Settings{}, fmt.Errorf("creating plain DNS dialer: %w", err)
|
||||
}
|
||||
default:
|
||||
panic("unknown upstream type: " + settings.UpstreamType)
|
||||
panic("unknown upstream type: " + userSettings.UpstreamType)
|
||||
}
|
||||
serverSettings.Dialer = dialer
|
||||
|
||||
if *settings.Caching {
|
||||
if *userSettings.Caching {
|
||||
lruCache, err := lru.New(lru.Settings{})
|
||||
if err != nil {
|
||||
return server.Settings{}, fmt.Errorf("creating LRU cache: %w", err)
|
||||
@@ -123,3 +116,46 @@ func buildServerSettings(settings settings.DNS,
|
||||
|
||||
return serverSettings, nil
|
||||
}
|
||||
|
||||
func buildProviders(userSettings settings.DNS, localSubnets []netip.Prefix,
|
||||
logger Logger,
|
||||
) (providers []provider.Provider) {
|
||||
providersCount := len(userSettings.Providers)
|
||||
if userSettings.UpstreamType == settings.DNSUpstreamTypePlain {
|
||||
providersCount += len(userSettings.UpstreamPlainAddresses)
|
||||
}
|
||||
providers = make([]provider.Provider, 0, providersCount)
|
||||
|
||||
providersData := provider.NewProviders()
|
||||
for _, providerName := range userSettings.Providers {
|
||||
provider, err := providersData.Get(providerName)
|
||||
if err != nil {
|
||||
panic(err) // this should already had been checked
|
||||
}
|
||||
providers = append(providers, provider)
|
||||
}
|
||||
|
||||
for _, addrPort := range userSettings.UpstreamPlainAddresses {
|
||||
addr := addrPort.Addr()
|
||||
if addr.IsPrivate() && !addr.IsLoopback() &&
|
||||
!slices.ContainsFunc(localSubnets, func(prefix netip.Prefix) bool {
|
||||
return prefix.Contains(addr)
|
||||
}) {
|
||||
logger.Warnf("DNS server address %s is not in local subnets, "+
|
||||
"make sure to specify it in FIREWALL_OUTBOUND_SUBNETS as %s",
|
||||
addr, netip.PrefixFrom(addr, addr.BitLen()))
|
||||
}
|
||||
|
||||
provider := provider.Provider{
|
||||
Name: addrPort.String(),
|
||||
}
|
||||
if addr.Is4() {
|
||||
provider.Plain.IPv4 = []netip.AddrPort{addrPort}
|
||||
} else {
|
||||
provider.Plain.IPv6 = []netip.AddrPort{addrPort}
|
||||
}
|
||||
providers = append(providers, provider)
|
||||
}
|
||||
|
||||
return providers
|
||||
}
|
||||
|
||||
@@ -3,16 +3,15 @@ package dns
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
|
||||
"github.com/qdm12/dns/v2/pkg/check"
|
||||
"github.com/qdm12/dns/v2/pkg/middlewares/filter/update"
|
||||
"github.com/qdm12/dns/v2/pkg/nameserver"
|
||||
"github.com/qdm12/dns/v2/pkg/server"
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
)
|
||||
|
||||
func (l *Loop) setupServer(ctx context.Context) (runError <-chan error, err error) {
|
||||
settings := l.GetSettings()
|
||||
func (l *Loop) setupServer(ctx context.Context, settings settings.DNS) (runError <-chan error, err error) {
|
||||
var updateSettings update.Settings
|
||||
updateSettings.SetRebindingProtectionExempt(settings.Blacklist.RebindingProtectionExemptHostnames)
|
||||
err = l.filter.Update(updateSettings)
|
||||
@@ -20,7 +19,7 @@ func (l *Loop) setupServer(ctx context.Context) (runError <-chan error, err erro
|
||||
return nil, fmt.Errorf("updating filter for rebinding protection: %w", err)
|
||||
}
|
||||
|
||||
serverSettings, err := buildServerSettings(settings, l.filter, l.localResolvers, l.logger)
|
||||
serverSettings, err := buildServerSettings(settings, l.filter, l.localResolvers, l.localSubnets, l.logger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("building server settings: %w", err)
|
||||
}
|
||||
@@ -37,12 +36,8 @@ func (l *Loop) setupServer(ctx context.Context) (runError <-chan error, err erro
|
||||
l.server = server
|
||||
|
||||
// use internal DNS server
|
||||
const defaultDNSPort = 53
|
||||
nameserver.UseDNSInternally(nameserver.SettingsInternalDNS{
|
||||
AddrPort: netip.AddrPortFrom(settings.ServerAddress, defaultDNSPort),
|
||||
})
|
||||
nameserver.UseDNSInternally(nameserver.SettingsInternalDNS{})
|
||||
err = nameserver.UseDNSSystemWide(nameserver.SettingsSystemDNS{
|
||||
IPs: []netip.Addr{settings.ServerAddress},
|
||||
ResolvPath: l.resolvConf,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -40,8 +40,6 @@ func (s *State) SetSettings(ctx context.Context, settings settings.DNS) (
|
||||
|
||||
// Restart
|
||||
_, _ = s.statusApplier.ApplyStatus(ctx, constants.Stopped)
|
||||
if *settings.ServerEnabled {
|
||||
outcome, _ = s.statusApplier.ApplyStatus(ctx, constants.Running)
|
||||
}
|
||||
outcome, _ = s.statusApplier.ApplyStatus(ctx, constants.Running)
|
||||
return outcome
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user