feat(dns): restrict plain DNS output traffic

This commit is contained in:
Quentin McGaw
2026-02-10 16:19:08 +00:00
parent b0a75673bd
commit db947c17a8
14 changed files with 360 additions and 47 deletions
+17
View File
@@ -0,0 +1,17 @@
package dns
import (
"context"
"net/netip"
)
type Logger interface {
Debug(s string)
Info(s string)
Warn(s string)
Error(s string)
}
type Firewall interface {
RestrictOutputAddrPort(ctx context.Context, addrPort netip.AddrPort) (err error)
}
-8
View File
@@ -1,8 +0,0 @@
package dns
type Logger interface {
Debug(s string)
Info(s string)
Warn(s string)
Error(s string)
}
+3 -1
View File
@@ -24,6 +24,7 @@ type Loop struct {
localResolvers []netip.Addr
resolvConf string
client *http.Client
firewall Firewall
logger Logger
userTrigger bool
start <-chan struct{}
@@ -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, firewall Firewall, logger Logger,
) (loop *Loop, err error) {
start := make(chan struct{})
running := make(chan models.LoopStatus)
@@ -64,6 +65,7 @@ func NewLoop(settings settings.DNS,
filter: filter,
resolvConf: "/etc/resolv.conf",
client: client,
firewall: firewall,
logger: logger,
userTrigger: true,
start: start,
+9 -2
View File
@@ -1,13 +1,14 @@
package dns
import (
"context"
"net/netip"
"time"
"github.com/qdm12/dns/v2/pkg/nameserver"
)
func (l *Loop) useUnencryptedDNS(fallback bool) {
func (l *Loop) useUnencryptedDNS(ctx context.Context, fallback bool) {
settings := l.GetSettings()
targetIP := settings.GetFirstPlaintextIPv4()
@@ -20,8 +21,9 @@ func (l *Loop) useUnencryptedDNS(fallback bool) {
const dialTimeout = 3 * time.Second
const defaultDNSPort = 53
addrPort := netip.AddrPortFrom(targetIP, defaultDNSPort)
settingsInternalDNS := nameserver.SettingsInternalDNS{
AddrPort: netip.AddrPortFrom(targetIP, defaultDNSPort),
AddrPort: addrPort,
Timeout: dialTimeout,
}
nameserver.UseDNSInternally(settingsInternalDNS)
@@ -34,4 +36,9 @@ func (l *Loop) useUnencryptedDNS(fallback bool) {
if err != nil {
l.logger.Error(err.Error())
}
err = l.firewall.RestrictOutputAddrPort(ctx, addrPort)
if err != nil {
l.logger.Error("restricting plain DNS traffic to " + targetIP.String() + ": " + err.Error())
}
}
+5 -5
View File
@@ -24,7 +24,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
"and go through your container network DNS outside the VPN tunnel!")
} else {
const fallback = false
l.useUnencryptedDNS(fallback)
l.useUnencryptedDNS(ctx, fallback)
}
select {
@@ -56,7 +56,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
if !errors.Is(err, errUpdateBlockLists) {
const fallback = true
l.useUnencryptedDNS(fallback)
l.useUnencryptedDNS(ctx, fallback)
}
l.logAndWait(ctx, err)
settings = l.GetSettings()
@@ -66,7 +66,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
settings = l.GetSettings()
if !*settings.KeepNameserver && !*settings.ServerEnabled {
const fallback = false
l.useUnencryptedDNS(fallback)
l.useUnencryptedDNS(ctx, fallback)
}
l.userTrigger = false
@@ -94,7 +94,7 @@ func (l *Loop) runWait(ctx context.Context, runError <-chan error) (exitLoop boo
settings := l.GetSettings()
if !*settings.KeepNameserver && *settings.ServerEnabled {
const fallback = false
l.useUnencryptedDNS(fallback)
l.useUnencryptedDNS(ctx, fallback)
l.stopServer()
}
l.stopped <- struct{}{}
@@ -105,7 +105,7 @@ func (l *Loop) runWait(ctx context.Context, runError <-chan error) (exitLoop boo
case err := <-runError: // unexpected error
l.statusManager.SetStatus(constants.Crashed)
const fallback = true
l.useUnencryptedDNS(fallback)
l.useUnencryptedDNS(ctx, fallback)
l.logAndWait(ctx, err)
return false
}
+7 -1
View File
@@ -39,8 +39,9 @@ func (l *Loop) setupServer(ctx context.Context) (runError <-chan error, err erro
// use internal DNS server
const defaultDNSPort = 53
addrPort := netip.AddrPortFrom(settings.ServerAddress, defaultDNSPort)
nameserver.UseDNSInternally(nameserver.SettingsInternalDNS{
AddrPort: netip.AddrPortFrom(settings.ServerAddress, defaultDNSPort),
AddrPort: addrPort,
})
err = nameserver.UseDNSSystemWide(nameserver.SettingsSystemDNS{
IPs: []netip.Addr{settings.ServerAddress},
@@ -50,6 +51,11 @@ func (l *Loop) setupServer(ctx context.Context) (runError <-chan error, err erro
l.logger.Error(err.Error())
}
err = l.firewall.RestrictOutputAddrPort(ctx, addrPort)
if err != nil {
l.logger.Error("restricting plain DNS traffic to " + addrPort.Addr().String() + ": " + err.Error())
}
err = check.WaitForDNS(ctx, check.Settings{})
if err != nil {
l.stopServer()