Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/gluetun/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
}

dnsLogger := logger.New(log.SetComponent("dns"))
dnsLooper, err := dns.NewLoop(allSettings.DNS, httpClient,
dnsLooper, err := dns.NewLoop(allSettings.DNS, httpClient, firewallConf,
dnsLogger)
if err != nil {
return fmt.Errorf("creating DNS loop: %w", err)
Expand Down
17 changes: 17 additions & 0 deletions internal/dns/interfaces.go
Original file line number Diff line number Diff line change
@@ -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 changes: 0 additions & 8 deletions internal/dns/logger.go

This file was deleted.

4 changes: 3 additions & 1 deletion internal/dns/loop.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Loop struct {
localResolvers []netip.Addr
resolvConf string
client *http.Client
firewall Firewall
logger Logger
userTrigger bool
start <-chan struct{}
Expand All @@ -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)
Expand All @@ -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,
Expand Down
11 changes: 9 additions & 2 deletions internal/dns/plaintext.go
Original file line number Diff line number Diff line change
@@ -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()
Expand All @@ -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)
Expand All @@ -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())
}
}
10 changes: 5 additions & 5 deletions internal/dns/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -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{}{}
Expand All @@ -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
}
Expand Down
8 changes: 7 additions & 1 deletion internal/dns/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions internal/firewall/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ func Test_deleteIPTablesRule(t *testing.T) {
"invalid_instruction": {
instruction: "invalid",
errWrapped: ErrIptablesCommandMalformed,
errMessage: "parsing iptables command: iptables command is malformed: " +
"fields count 1 is not even: \"invalid\"",
errMessage: "parsing iptables command: parsing \"invalid\": " +
"iptables command is malformed: flag \"invalid\" requires a value, but got none",
},
"list_error": {
instruction: "-t nat --delete PREROUTING -i tun0 -p tcp --dport 43716 -j REDIRECT --to-ports 5678",
Expand Down
2 changes: 2 additions & 0 deletions internal/firewall/firewall.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Config struct {
outboundSubnets []netip.Prefix
allowedInputPorts map[uint16]map[string]struct{} // port to interfaces set mapping
portRedirections portRedirections
outputAddrPort map[uint16]netip.Addr
stateMutex sync.Mutex
}

Expand All @@ -52,6 +53,7 @@ func NewConfig(ctx context.Context, logger Logger,
runner: runner,
logger: logger,
allowedInputPorts: make(map[uint16]map[string]struct{}),
outputAddrPort: make(map[uint16]netip.Addr),
ipTables: iptables,
ip6Tables: ip6tables,
customRulesPath: "/iptables/post-rules.txt",
Expand Down
13 changes: 13 additions & 0 deletions internal/firewall/iptablesmix.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package firewall

import (
"context"
"fmt"
)

func (c *Config) runMixedIptablesInstructions(ctx context.Context, instructions []string) error {
Expand All @@ -19,3 +20,15 @@ func (c *Config) runMixedIptablesInstruction(ctx context.Context, instruction st
}
return c.runIP6tablesInstruction(ctx, instruction)
}

func (c *Config) runIPv4AndV6IptablesInstructions(ctx context.Context,
ipv4Instructions, ipv6Instructions []string,
) error {
if err := c.runIptablesInstructions(ctx, ipv4Instructions); err != nil {
return fmt.Errorf("running iptables instructions: %w", err)
}
if err := c.runIP6tablesInstructions(ctx, ipv6Instructions); err != nil {
return fmt.Errorf("running ip6tables instructions: %w", err)
}
return nil
}
Loading
Loading