diff --git a/internal/dns/loop.go b/internal/dns/loop.go index a76bbe50..f421165e 100644 --- a/internal/dns/loop.go +++ b/internal/dns/loop.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "net/netip" "time" "github.com/qdm12/dns/v2/pkg/middlewares/filter/mapfilter" @@ -16,22 +17,23 @@ import ( ) type Loop struct { - statusManager *loopstate.State - state *state.State - server *server.Server - filter *mapfilter.Filter - resolvConf string - client *http.Client - logger Logger - userTrigger bool - start <-chan struct{} - running chan<- models.LoopStatus - stop <-chan struct{} - stopped chan<- struct{} - updateTicker <-chan struct{} - backoffTime time.Duration - timeNow func() time.Time - timeSince func(time.Time) time.Duration + statusManager *loopstate.State + state *state.State + server *server.Server + filter *mapfilter.Filter + localResolvers []netip.AddrPort + resolvConf string + client *http.Client + logger Logger + userTrigger bool + start <-chan struct{} + running chan<- models.LoopStatus + stop <-chan struct{} + stopped chan<- struct{} + updateTicker <-chan struct{} + backoffTime time.Duration + timeNow func() time.Time + timeSince func(time.Time) time.Duration } const defaultBackoffTime = 10 * time.Second diff --git a/internal/dns/run.go b/internal/dns/run.go index 652c205f..fab5d5c9 100644 --- a/internal/dns/run.go +++ b/internal/dns/run.go @@ -4,12 +4,15 @@ import ( "context" "errors" + "github.com/qdm12/dns/v2/pkg/nameserver" "github.com/qdm12/gluetun/internal/constants" ) func (l *Loop) Run(ctx context.Context, done chan<- struct{}) { defer close(done) + l.localResolvers = nameserver.GetPrivateDNSServers() + if *l.GetSettings().KeepNameserver { l.logger.Warn("⚠️⚠️⚠️ keeping the default container nameservers, " + "this will likely leak DNS traffic outside the VPN " + diff --git a/internal/dns/settings.go b/internal/dns/settings.go index ae3bb6a4..bb7faf53 100644 --- a/internal/dns/settings.go +++ b/internal/dns/settings.go @@ -3,6 +3,7 @@ package dns import ( "context" "fmt" + "net/netip" "github.com/qdm12/dns/v2/pkg/doh" "github.com/qdm12/dns/v2/pkg/dot" @@ -10,6 +11,7 @@ import ( "github.com/qdm12/dns/v2/pkg/middlewares/cache/lru" filtermiddleware "github.com/qdm12/dns/v2/pkg/middlewares/filter" "github.com/qdm12/dns/v2/pkg/middlewares/filter/mapfilter" + "github.com/qdm12/dns/v2/pkg/middlewares/localdns" "github.com/qdm12/dns/v2/pkg/plain" "github.com/qdm12/dns/v2/pkg/provider" "github.com/qdm12/dns/v2/pkg/server" @@ -25,7 +27,8 @@ func (l *Loop) SetSettings(ctx context.Context, settings settings.DNS) ( } func buildServerSettings(settings settings.DNS, - filter *mapfilter.Filter, logger Logger) ( + filter *mapfilter.Filter, localResolvers []netip.AddrPort, + logger Logger) ( serverSettings server.Settings, err error, ) { serverSettings.Logger = logger @@ -101,5 +104,17 @@ func buildServerSettings(settings settings.DNS, } serverSettings.Middlewares = append(serverSettings.Middlewares, filterMiddleware) + localDNSMiddleware, err := localdns.New(localdns.Settings{ + Resolvers: localResolvers, // auto-detected at container start only + Logger: logger, + }) + if err != nil { + return server.Settings{}, fmt.Errorf("creating local DNS middleware: %w", err) + } + // Place after cache middleware, since we want to avoid caching for local + // hostnames that may change regularly. + // Place after filter middleware to avoid conflicts with the rebinding protection. + serverSettings.Middlewares = append(serverSettings.Middlewares, localDNSMiddleware) + return serverSettings, nil } diff --git a/internal/dns/setup.go b/internal/dns/setup.go index 2fc1f03f..f93004a7 100644 --- a/internal/dns/setup.go +++ b/internal/dns/setup.go @@ -21,7 +21,7 @@ func (l *Loop) setupServer(ctx context.Context) (runError <-chan error, err erro settings := l.GetSettings() - serverSettings, err := buildServerSettings(settings, l.filter, l.logger) + serverSettings, err := buildServerSettings(settings, l.filter, l.localResolvers, l.logger) if err != nil { return nil, fmt.Errorf("building server settings: %w", err) }