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:
+1
-3
@@ -175,7 +175,6 @@ ENV VPN_SERVICE_PROVIDER=pia \
|
|||||||
HEALTH_SMALL_CHECK_TYPE=icmp \
|
HEALTH_SMALL_CHECK_TYPE=icmp \
|
||||||
HEALTH_RESTART_VPN=on \
|
HEALTH_RESTART_VPN=on \
|
||||||
# DNS
|
# DNS
|
||||||
DNS_SERVER=on \
|
|
||||||
DNS_UPSTREAM_RESOLVER_TYPE=DoT \
|
DNS_UPSTREAM_RESOLVER_TYPE=DoT \
|
||||||
DNS_UPSTREAM_RESOLVERS=cloudflare \
|
DNS_UPSTREAM_RESOLVERS=cloudflare \
|
||||||
DNS_BLOCK_IPS= \
|
DNS_BLOCK_IPS= \
|
||||||
@@ -188,8 +187,7 @@ ENV VPN_SERVICE_PROVIDER=pia \
|
|||||||
DNS_UNBLOCK_HOSTNAMES= \
|
DNS_UNBLOCK_HOSTNAMES= \
|
||||||
DNS_REBINDING_PROTECTION_EXEMPT_HOSTNAMES= \
|
DNS_REBINDING_PROTECTION_EXEMPT_HOSTNAMES= \
|
||||||
DNS_UPDATE_PERIOD=24h \
|
DNS_UPDATE_PERIOD=24h \
|
||||||
DNS_ADDRESS=127.0.0.1 \
|
DNS_UPSTREAM_PLAIN_ADDRESSES= \
|
||||||
DNS_KEEP_NAMESERVER=off \
|
|
||||||
# HTTP proxy
|
# HTTP proxy
|
||||||
HTTPPROXY= \
|
HTTPPROXY= \
|
||||||
HTTPPROXY_LOG=off \
|
HTTPPROXY_LOG=off \
|
||||||
|
|||||||
+9
-1
@@ -402,7 +402,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
|
|
||||||
dnsLogger := logger.New(log.SetComponent("dns"))
|
dnsLogger := logger.New(log.SetComponent("dns"))
|
||||||
dnsLooper, err := dns.NewLoop(allSettings.DNS, httpClient,
|
dnsLooper, err := dns.NewLoop(allSettings.DNS, httpClient,
|
||||||
dnsLogger)
|
dnsLogger, localNetworksToPrefixes(localNetworks))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("creating DNS loop: %w", err)
|
return fmt.Errorf("creating DNS loop: %w", err)
|
||||||
}
|
}
|
||||||
@@ -567,6 +567,14 @@ func printVersions(ctx context.Context, logger infoer,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func localNetworksToPrefixes(localNetworks []routing.LocalNetwork) (prefixes []netip.Prefix) {
|
||||||
|
prefixes = make([]netip.Prefix, len(localNetworks))
|
||||||
|
for i, localNetwork := range localNetworks {
|
||||||
|
prefixes[i] = localNetwork.IPNet
|
||||||
|
}
|
||||||
|
return prefixes
|
||||||
|
}
|
||||||
|
|
||||||
type netLinker interface {
|
type netLinker interface {
|
||||||
Addresser
|
Addresser
|
||||||
Router
|
Router
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ require (
|
|||||||
github.com/mdlayher/genetlink v1.3.2
|
github.com/mdlayher/genetlink v1.3.2
|
||||||
github.com/mdlayher/netlink v1.7.2
|
github.com/mdlayher/netlink v1.7.2
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4
|
github.com/pelletier/go-toml/v2 v2.2.4
|
||||||
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260216151239-36b3306f2205
|
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260227125914-6dbc4b280dc6
|
||||||
github.com/qdm12/gosettings v0.4.4
|
github.com/qdm12/gosettings v0.4.4
|
||||||
github.com/qdm12/goshutdown v0.3.0
|
github.com/qdm12/goshutdown v0.3.0
|
||||||
github.com/qdm12/gosplash v0.2.1-0.20260305164749-b713de4fee6c
|
github.com/qdm12/gosplash v0.2.1-0.20260305164749-b713de4fee6c
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPA
|
|||||||
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260216151239-36b3306f2205 h1:0ycKUDQ50cYb2QpeyGcEnvVs9HJmC9jsb/XZNC1z28c=
|
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260227125914-6dbc4b280dc6 h1:N0UtsWF8NS1YuQ18Ws3hrhRAPmngoCns4KxoQjAcwaw=
|
||||||
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260216151239-36b3306f2205/go.mod h1:98foWgXJZ+g8gJIuO+fdO+oWpFei5WShMFTeN4Im2lE=
|
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260227125914-6dbc4b280dc6/go.mod h1:98foWgXJZ+g8gJIuO+fdO+oWpFei5WShMFTeN4Im2lE=
|
||||||
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978 h1:TRGpCU1l0lNwtogEUSs5U+RFceYxkAJUmrGabno7J5c=
|
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978 h1:TRGpCU1l0lNwtogEUSs5U+RFceYxkAJUmrGabno7J5c=
|
||||||
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978/go.mod h1:D1Po4CRQLYjccnAR2JsVlN1sBMgQrcNLONbvyuzcdTg=
|
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978/go.mod h1:D1Po4CRQLYjccnAR2JsVlN1sBMgQrcNLONbvyuzcdTg=
|
||||||
github.com/qdm12/gosettings v0.4.4 h1:SM6tOZDf6k8qbjWU8KWyBF4mWIixfsKCfh9DGRLHlj4=
|
github.com/qdm12/gosettings v0.4.4 h1:SM6tOZDf6k8qbjWU8KWyBF4mWIixfsKCfh9DGRLHlj4=
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ func readObsolete(r *reader.Reader) (warnings []string) {
|
|||||||
"DOT_VALIDATION_LOGLEVEL": "DOT_VALIDATION_LOGLEVEL is obsolete because DNSSEC validation is not implemented.",
|
"DOT_VALIDATION_LOGLEVEL": "DOT_VALIDATION_LOGLEVEL is obsolete because DNSSEC validation is not implemented.",
|
||||||
"HEALTH_VPN_DURATION_INITIAL": "HEALTH_VPN_DURATION_INITIAL is obsolete",
|
"HEALTH_VPN_DURATION_INITIAL": "HEALTH_VPN_DURATION_INITIAL is obsolete",
|
||||||
"HEALTH_VPN_DURATION_ADDITION": "HEALTH_VPN_DURATION_ADDITION is obsolete",
|
"HEALTH_VPN_DURATION_ADDITION": "HEALTH_VPN_DURATION_ADDITION is obsolete",
|
||||||
|
"DNS_SERVER": "DNS_SERVER is obsolete because the forwarding server is always enabled.",
|
||||||
|
"DOT": "DOT is obsolete because the forwarding server is always enabled.",
|
||||||
|
"DNS_KEEP_NAMESERVER": "DNS_KEEP_NAMESERVER is obsolete because the forwarding server is always used and " +
|
||||||
|
"forwards local names to private DNS resolvers found in /etc/resolv.conf",
|
||||||
}
|
}
|
||||||
sortedKeys := maps.Keys(keyToMessage)
|
sortedKeys := maps.Keys(keyToMessage)
|
||||||
slices.Sort(sortedKeys)
|
slices.Sort(sortedKeys)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/dns/v2/pkg/provider"
|
"github.com/qdm12/dns/v2/pkg/provider"
|
||||||
@@ -13,20 +14,25 @@ import (
|
|||||||
"github.com/qdm12/gotree"
|
"github.com/qdm12/gotree"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DNSUpstreamTypeDot = "dot"
|
||||||
|
DNSUpstreamTypeDoh = "doh"
|
||||||
|
DNSUpstreamTypePlain = "plain"
|
||||||
|
)
|
||||||
|
|
||||||
// DNS contains settings to configure DNS.
|
// DNS contains settings to configure DNS.
|
||||||
type DNS struct {
|
type DNS struct {
|
||||||
// ServerEnabled is true if the server should be running
|
// UpstreamType can be [DNSUpstreamTypeDot], [DNSUpstreamTypeDoh]
|
||||||
// and used. It defaults to true, and cannot be nil
|
// or [DNSUpstreamTypePlain]. It defaults to [DNSUpstreamTypeDot].
|
||||||
// in the internal state.
|
|
||||||
ServerEnabled *bool
|
|
||||||
// UpstreamType can be dot or plain, and defaults to dot.
|
|
||||||
UpstreamType string `json:"upstream_type"`
|
UpstreamType string `json:"upstream_type"`
|
||||||
// UpdatePeriod is the period to update DNS block lists.
|
// UpdatePeriod is the period to update DNS block lists.
|
||||||
// It can be set to 0 to disable the update.
|
// It can be set to 0 to disable the update.
|
||||||
// It defaults to 24h and cannot be nil in
|
// It defaults to 24h and cannot be nil in
|
||||||
// the internal state.
|
// the internal state.
|
||||||
UpdatePeriod *time.Duration
|
UpdatePeriod *time.Duration
|
||||||
// Providers is a list of DNS providers
|
// Providers is a list of DNS providers.
|
||||||
|
// It defaults to either ["cloudflare"] or [] if the
|
||||||
|
// UpstreamPlainAddresses field is set.
|
||||||
Providers []string `json:"providers"`
|
Providers []string `json:"providers"`
|
||||||
// Caching is true if the server should cache
|
// Caching is true if the server should cache
|
||||||
// DNS responses.
|
// DNS responses.
|
||||||
@@ -36,32 +42,23 @@ type DNS struct {
|
|||||||
// Blacklist contains settings to configure the filter
|
// Blacklist contains settings to configure the filter
|
||||||
// block lists.
|
// block lists.
|
||||||
Blacklist DNSBlacklist
|
Blacklist DNSBlacklist
|
||||||
// ServerAddress is the DNS server to use inside
|
// UpstreamPlainAddresses are the upstream plaintext DNS resolver
|
||||||
// the Go program and for the system.
|
// addresses to use by the built-in DNS server forwarder.
|
||||||
// It defaults to '127.0.0.1' to be used with the
|
// Note, if the upstream type is [dnsUpstreamTypePlain] these are merged
|
||||||
// local server. It cannot be the zero value in the internal
|
// together with provider names set in the Providers field.
|
||||||
// state.
|
// If this field is set, the Providers field will default to the empty slice.
|
||||||
ServerAddress netip.Addr
|
UpstreamPlainAddresses []netip.AddrPort
|
||||||
// KeepNameserver is true if the existing DNS server
|
|
||||||
// found in /etc/resolv.conf should be used
|
|
||||||
// Note setting this to true will likely DNS traffic
|
|
||||||
// outside the VPN tunnel since it would go through
|
|
||||||
// the local DNS server of your Docker/Kubernetes
|
|
||||||
// configuration, which is likely not going through the tunnel.
|
|
||||||
// This will also disable the DNS forwarder server and the
|
|
||||||
// `ServerAddress` field will be ignored.
|
|
||||||
// It defaults to false and cannot be nil in the
|
|
||||||
// internal state.
|
|
||||||
KeepNameserver *bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrDNSUpstreamTypeNotValid = errors.New("DNS upstream type is not valid")
|
ErrDNSUpstreamTypeNotValid = errors.New("DNS upstream type is not valid")
|
||||||
ErrDNSUpdatePeriodTooShort = errors.New("update period is too short")
|
ErrDNSUpdatePeriodTooShort = errors.New("update period is too short")
|
||||||
|
ErrDNSUpstreamPlainNoIPv6 = errors.New("upstream plain addresses do not contain any IPv6 address")
|
||||||
|
ErrDNSUpstreamPlainNoIPv4 = errors.New("upstream plain addresses do not contain any IPv4 address")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d DNS) validate() (err error) {
|
func (d DNS) validate() (err error) {
|
||||||
if !helpers.IsOneOf(d.UpstreamType, "dot", "doh", "plain") {
|
if !helpers.IsOneOf(d.UpstreamType, DNSUpstreamTypeDot, DNSUpstreamTypeDoh, DNSUpstreamTypePlain) {
|
||||||
return fmt.Errorf("%w: %s", ErrDNSUpstreamTypeNotValid, d.UpstreamType)
|
return fmt.Errorf("%w: %s", ErrDNSUpstreamTypeNotValid, d.UpstreamType)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +76,18 @@ func (d DNS) validate() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.UpstreamType == DNSUpstreamTypePlain {
|
||||||
|
if *d.IPv6 && !slices.ContainsFunc(d.UpstreamPlainAddresses, func(addrPort netip.AddrPort) bool {
|
||||||
|
return addrPort.Addr().Is6()
|
||||||
|
}) {
|
||||||
|
return fmt.Errorf("%w: in %d addresses", ErrDNSUpstreamPlainNoIPv6, len(d.UpstreamPlainAddresses))
|
||||||
|
} else if !slices.ContainsFunc(d.UpstreamPlainAddresses, func(addrPort netip.AddrPort) bool {
|
||||||
|
return addrPort.Addr().Is4()
|
||||||
|
}) {
|
||||||
|
return fmt.Errorf("%w: in %d addresses", ErrDNSUpstreamPlainNoIPv4, len(d.UpstreamPlainAddresses))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = d.Blacklist.validate()
|
err = d.Blacklist.validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -89,15 +98,13 @@ func (d DNS) validate() (err error) {
|
|||||||
|
|
||||||
func (d *DNS) Copy() (copied DNS) {
|
func (d *DNS) Copy() (copied DNS) {
|
||||||
return DNS{
|
return DNS{
|
||||||
ServerEnabled: gosettings.CopyPointer(d.ServerEnabled),
|
UpstreamType: d.UpstreamType,
|
||||||
UpstreamType: d.UpstreamType,
|
UpdatePeriod: gosettings.CopyPointer(d.UpdatePeriod),
|
||||||
UpdatePeriod: gosettings.CopyPointer(d.UpdatePeriod),
|
Providers: gosettings.CopySlice(d.Providers),
|
||||||
Providers: gosettings.CopySlice(d.Providers),
|
Caching: gosettings.CopyPointer(d.Caching),
|
||||||
Caching: gosettings.CopyPointer(d.Caching),
|
IPv6: gosettings.CopyPointer(d.IPv6),
|
||||||
IPv6: gosettings.CopyPointer(d.IPv6),
|
Blacklist: d.Blacklist.copy(),
|
||||||
Blacklist: d.Blacklist.copy(),
|
UpstreamPlainAddresses: d.UpstreamPlainAddresses,
|
||||||
ServerAddress: d.ServerAddress,
|
|
||||||
KeepNameserver: gosettings.CopyPointer(d.KeepNameserver),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,20 +112,17 @@ func (d *DNS) Copy() (copied DNS) {
|
|||||||
// settings object with any field set in the other
|
// settings object with any field set in the other
|
||||||
// settings.
|
// settings.
|
||||||
func (d *DNS) overrideWith(other DNS) {
|
func (d *DNS) overrideWith(other DNS) {
|
||||||
d.ServerEnabled = gosettings.OverrideWithPointer(d.ServerEnabled, other.ServerEnabled)
|
|
||||||
d.UpstreamType = gosettings.OverrideWithComparable(d.UpstreamType, other.UpstreamType)
|
d.UpstreamType = gosettings.OverrideWithComparable(d.UpstreamType, other.UpstreamType)
|
||||||
d.UpdatePeriod = gosettings.OverrideWithPointer(d.UpdatePeriod, other.UpdatePeriod)
|
d.UpdatePeriod = gosettings.OverrideWithPointer(d.UpdatePeriod, other.UpdatePeriod)
|
||||||
d.Providers = gosettings.OverrideWithSlice(d.Providers, other.Providers)
|
d.Providers = gosettings.OverrideWithSlice(d.Providers, other.Providers)
|
||||||
d.Caching = gosettings.OverrideWithPointer(d.Caching, other.Caching)
|
d.Caching = gosettings.OverrideWithPointer(d.Caching, other.Caching)
|
||||||
d.IPv6 = gosettings.OverrideWithPointer(d.IPv6, other.IPv6)
|
d.IPv6 = gosettings.OverrideWithPointer(d.IPv6, other.IPv6)
|
||||||
d.Blacklist.overrideWith(other.Blacklist)
|
d.Blacklist.overrideWith(other.Blacklist)
|
||||||
d.ServerAddress = gosettings.OverrideWithValidator(d.ServerAddress, other.ServerAddress)
|
d.UpstreamPlainAddresses = gosettings.OverrideWithSlice(d.UpstreamPlainAddresses, other.UpstreamPlainAddresses)
|
||||||
d.KeepNameserver = gosettings.OverrideWithPointer(d.KeepNameserver, other.KeepNameserver)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNS) setDefaults() {
|
func (d *DNS) setDefaults() {
|
||||||
d.ServerEnabled = gosettings.DefaultPointer(d.ServerEnabled, true)
|
d.UpstreamType = gosettings.DefaultComparable(d.UpstreamType, DNSUpstreamTypeDot)
|
||||||
d.UpstreamType = gosettings.DefaultComparable(d.UpstreamType, "dot")
|
|
||||||
const defaultUpdatePeriod = 24 * time.Hour
|
const defaultUpdatePeriod = 24 * time.Hour
|
||||||
d.UpdatePeriod = gosettings.DefaultPointer(d.UpdatePeriod, defaultUpdatePeriod)
|
d.UpdatePeriod = gosettings.DefaultPointer(d.UpdatePeriod, defaultUpdatePeriod)
|
||||||
d.Providers = gosettings.DefaultSlice(d.Providers, []string{
|
d.Providers = gosettings.DefaultSlice(d.Providers, []string{
|
||||||
@@ -127,26 +131,53 @@ func (d *DNS) setDefaults() {
|
|||||||
d.Caching = gosettings.DefaultPointer(d.Caching, true)
|
d.Caching = gosettings.DefaultPointer(d.Caching, true)
|
||||||
d.IPv6 = gosettings.DefaultPointer(d.IPv6, false)
|
d.IPv6 = gosettings.DefaultPointer(d.IPv6, false)
|
||||||
d.Blacklist.setDefaults()
|
d.Blacklist.setDefaults()
|
||||||
d.ServerAddress = gosettings.DefaultValidator(d.ServerAddress,
|
d.UpstreamPlainAddresses = gosettings.DefaultSlice(d.UpstreamPlainAddresses, []netip.AddrPort{})
|
||||||
netip.AddrFrom4([4]byte{127, 0, 0, 1}))
|
}
|
||||||
d.KeepNameserver = gosettings.DefaultPointer(d.KeepNameserver, false)
|
|
||||||
|
func defaultDNSProviders() []string {
|
||||||
|
return []string{
|
||||||
|
provider.Cloudflare().Name,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d DNS) GetFirstPlaintextIPv4() (ipv4 netip.Addr) {
|
func (d DNS) GetFirstPlaintextIPv4() (ipv4 netip.Addr) {
|
||||||
localhost := netip.AddrFrom4([4]byte{127, 0, 0, 1})
|
if d.UpstreamType == DNSUpstreamTypePlain {
|
||||||
if d.ServerAddress.Compare(localhost) != 0 && d.ServerAddress.Is4() {
|
for _, addrPort := range d.UpstreamPlainAddresses {
|
||||||
return d.ServerAddress
|
if addrPort.Addr().Is4() {
|
||||||
|
return addrPort.Addr()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipv4 = findPlainIPv4InProviders(d.Providers)
|
||||||
|
if ipv4.IsValid() {
|
||||||
|
return ipv4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either:
|
||||||
|
// - all upstream plain addresses are IPv6 and no provider is set
|
||||||
|
// - all providers set do not have a plaintext IPv4 address
|
||||||
|
ipv4 = findPlainIPv4InProviders(defaultDNSProviders())
|
||||||
|
if !ipv4.IsValid() {
|
||||||
|
panic("no plaintext IPv4 address found in default DNS providers")
|
||||||
|
}
|
||||||
|
return ipv4
|
||||||
|
}
|
||||||
|
|
||||||
|
func findPlainIPv4InProviders(providerNames []string) netip.Addr {
|
||||||
providers := provider.NewProviders()
|
providers := provider.NewProviders()
|
||||||
provider, err := providers.Get(d.Providers[0])
|
for _, name := range providerNames {
|
||||||
if err != nil {
|
provider, err := providers.Get(name)
|
||||||
// Settings should be validated before calling this function,
|
if err != nil {
|
||||||
// so an error happening here is a programming error.
|
// Settings should be validated before calling this function,
|
||||||
panic(err)
|
// so an error happening here is a programming error.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if len(provider.Plain.IPv4) > 0 {
|
||||||
|
return provider.Plain.IPv4[0].Addr()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return netip.Addr{}
|
||||||
return provider.Plain.IPv4[0].Addr()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d DNS) String() string {
|
func (d DNS) String() string {
|
||||||
@@ -155,22 +186,22 @@ func (d DNS) String() string {
|
|||||||
|
|
||||||
func (d DNS) toLinesNode() (node *gotree.Node) {
|
func (d DNS) toLinesNode() (node *gotree.Node) {
|
||||||
node = gotree.New("DNS settings:")
|
node = gotree.New("DNS settings:")
|
||||||
node.Appendf("Keep existing nameserver(s): %s", gosettings.BoolToYesNo(d.KeepNameserver))
|
|
||||||
if *d.KeepNameserver {
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
node.Appendf("DNS server address to use: %s", d.ServerAddress)
|
|
||||||
|
|
||||||
node.Appendf("DNS forwarder server enabled: %s", gosettings.BoolToYesNo(d.ServerEnabled))
|
|
||||||
if !*d.ServerEnabled {
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
|
|
||||||
node.Appendf("Upstream resolver type: %s", d.UpstreamType)
|
node.Appendf("Upstream resolver type: %s", d.UpstreamType)
|
||||||
|
|
||||||
upstreamResolvers := node.Append("Upstream resolvers:")
|
upstreamResolvers := node.Append("Upstream resolvers:")
|
||||||
for _, provider := range d.Providers {
|
if len(d.UpstreamPlainAddresses) > 0 {
|
||||||
upstreamResolvers.Append(provider)
|
if d.UpstreamType == DNSUpstreamTypePlain {
|
||||||
|
for _, addr := range d.UpstreamPlainAddresses {
|
||||||
|
upstreamResolvers.Append(addr.String())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node.Appendf("Upstream plain addresses: ignored because upstream type is not plain")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, provider := range d.Providers {
|
||||||
|
upstreamResolvers.Append(provider)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.Appendf("Caching: %s", gosettings.BoolToYesNo(d.Caching))
|
node.Appendf("Caching: %s", gosettings.BoolToYesNo(d.Caching))
|
||||||
@@ -188,11 +219,6 @@ func (d DNS) toLinesNode() (node *gotree.Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNS) read(r *reader.Reader) (err error) {
|
func (d *DNS) read(r *reader.Reader) (err error) {
|
||||||
d.ServerEnabled, err = r.BoolPtr("DNS_SERVER", reader.RetroKeys("DOT"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.UpstreamType = r.String("DNS_UPSTREAM_RESOLVER_TYPE")
|
d.UpstreamType = r.String("DNS_UPSTREAM_RESOLVER_TYPE")
|
||||||
|
|
||||||
d.UpdatePeriod, err = r.DurationPtr("DNS_UPDATE_PERIOD")
|
d.UpdatePeriod, err = r.DurationPtr("DNS_UPDATE_PERIOD")
|
||||||
@@ -217,15 +243,43 @@ func (d *DNS) read(r *reader.Reader) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
d.ServerAddress, err = r.NetipAddr("DNS_ADDRESS", reader.RetroKeys("DNS_PLAINTEXT_ADDRESS"))
|
err = d.readUpstreamPlainAddresses(r)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.KeepNameserver, err = r.BoolPtr("DNS_KEEP_NAMESERVER")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DNS) readUpstreamPlainAddresses(r *reader.Reader) (err error) {
|
||||||
|
// If DNS_UPSTREAM_PLAIN_ADDRESSES is set, the user must also set DNS_UPSTREAM_TYPE=plain
|
||||||
|
// for these to be used. This is an added safety measure to reduce misunderstandings, and
|
||||||
|
// reduce odd settings overrides.
|
||||||
|
d.UpstreamPlainAddresses, err = r.CSVNetipAddrPorts("DNS_UPSTREAM_PLAIN_ADDRESSES")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retro-compatibility - remove in v4
|
||||||
|
// If DNS_ADDRESS is set to a non-localhost address, append it to the other
|
||||||
|
// upstream plain addresses, assuming port 53, and force the upstream type to plain AND
|
||||||
|
// clear any user picked providers, to maintain retro-compatibility behavior.
|
||||||
|
serverAddress, err := r.NetipAddr("DNS_ADDRESS",
|
||||||
|
reader.RetroKeys("DNS_PLAINTEXT_ADDRESS"),
|
||||||
|
reader.IsRetro("DNS_UPSTREAM_PLAIN_ADDRESSES"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !serverAddress.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
isLocalhost := serverAddress.Compare(netip.AddrFrom4([4]byte{127, 0, 0, 1})) == 0
|
||||||
|
if isLocalhost {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
const defaultPlainPort = 53
|
||||||
|
addrPort := netip.AddrPortFrom(serverAddress, defaultPlainPort)
|
||||||
|
d.UpstreamPlainAddresses = append(d.UpstreamPlainAddresses, addrPort)
|
||||||
|
d.UpstreamType = DNSUpstreamTypePlain
|
||||||
|
d.Providers = []string{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/qdm12/dns/v2/pkg/provider"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_defaultDNSProviders(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
names := defaultDNSProviders()
|
||||||
|
|
||||||
|
found := false
|
||||||
|
providers := provider.NewProviders()
|
||||||
|
for _, name := range names {
|
||||||
|
provider, err := providers.Get(name)
|
||||||
|
require.NoError(t, err)
|
||||||
|
if len(provider.Plain.IPv4) > 0 {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require.True(t, found, "no default DNS provider has a plaintext IPv4 address")
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package settings
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
|
"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
|
||||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||||
@@ -180,13 +179,11 @@ func (s Settings) Warnings() (warnings []string) {
|
|||||||
"by creating an issue, attaching the new certificate and we will update Gluetun.")
|
"by creating an issue, attaching the new certificate and we will update Gluetun.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove in v4
|
for _, upstreamAddress := range s.DNS.UpstreamPlainAddresses {
|
||||||
if s.DNS.ServerAddress.Unmap().Compare(netip.AddrFrom4([4]byte{127, 0, 0, 1})) != 0 {
|
if upstreamAddress.Addr().IsPrivate() {
|
||||||
warnings = append(warnings, "DNS address is set to "+s.DNS.ServerAddress.String()+
|
warnings = append(warnings, "DNS upstream address "+upstreamAddress.String()+" is private: "+
|
||||||
" so the local forwarding DNS server will not be used."+
|
"DNS traffic might leak out of the VPN tunnel to that address.")
|
||||||
" The default value changed to 127.0.0.1 so it uses the internal DNS server."+
|
}
|
||||||
" If this server fails to start, the IPv4 address of the first plaintext DNS server"+
|
|
||||||
" corresponding to the first DNS provider chosen is used.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return warnings
|
return warnings
|
||||||
|
|||||||
@@ -51,9 +51,6 @@ func Test_Settings_String(t *testing.T) {
|
|||||||
| ├── [2606:4700:4700::1111]:443
|
| ├── [2606:4700:4700::1111]:443
|
||||||
| └── [2001:4860:4860::8888]:443
|
| └── [2001:4860:4860::8888]:443
|
||||||
├── DNS settings:
|
├── DNS settings:
|
||||||
| ├── Keep existing nameserver(s): no
|
|
||||||
| ├── DNS server address to use: 127.0.0.1
|
|
||||||
| ├── DNS forwarder server enabled: yes
|
|
||||||
| ├── Upstream resolver type: dot
|
| ├── Upstream resolver type: dot
|
||||||
| ├── Upstream resolvers:
|
| ├── Upstream resolvers:
|
||||||
| | └── Cloudflare
|
| | └── Cloudflare
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package dns
|
|||||||
type Logger interface {
|
type Logger interface {
|
||||||
Debug(s string)
|
Debug(s string)
|
||||||
Info(s string)
|
Info(s string)
|
||||||
|
Infof(format string, args ...any)
|
||||||
Warn(s string)
|
Warn(s string)
|
||||||
|
Warnf(format string, args ...any)
|
||||||
Error(s string)
|
Error(s string)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type Loop struct {
|
|||||||
server *server.Server
|
server *server.Server
|
||||||
filter *mapfilter.Filter
|
filter *mapfilter.Filter
|
||||||
localResolvers []netip.Addr
|
localResolvers []netip.Addr
|
||||||
|
localSubnets []netip.Prefix
|
||||||
resolvConf string
|
resolvConf string
|
||||||
client *http.Client
|
client *http.Client
|
||||||
logger Logger
|
logger Logger
|
||||||
@@ -39,7 +40,7 @@ type Loop struct {
|
|||||||
const defaultBackoffTime = 10 * time.Second
|
const defaultBackoffTime = 10 * time.Second
|
||||||
|
|
||||||
func NewLoop(settings settings.DNS,
|
func NewLoop(settings settings.DNS,
|
||||||
client *http.Client, logger Logger,
|
client *http.Client, logger Logger, localSubnets []netip.Prefix,
|
||||||
) (loop *Loop, err error) {
|
) (loop *Loop, err error) {
|
||||||
start := make(chan struct{})
|
start := make(chan struct{})
|
||||||
running := make(chan models.LoopStatus)
|
running := make(chan models.LoopStatus)
|
||||||
@@ -62,6 +63,7 @@ func NewLoop(settings settings.DNS,
|
|||||||
state: state,
|
state: state,
|
||||||
server: nil,
|
server: nil,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
|
localSubnets: localSubnets,
|
||||||
resolvConf: "/etc/resolv.conf",
|
resolvConf: "/etc/resolv.conf",
|
||||||
client: client,
|
client: client,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
|||||||
+11
-30
@@ -17,14 +17,8 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if *l.GetSettings().KeepNameserver {
|
const fallback = false
|
||||||
l.logger.Warn("⚠️⚠️⚠️ keeping the default container nameservers, " +
|
l.useUnencryptedDNS(fallback)
|
||||||
"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)
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-l.start:
|
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
|
// Their values are to be used if DOT=off
|
||||||
var runError <-chan error
|
var runError <-chan error
|
||||||
|
|
||||||
settings := l.GetSettings()
|
for {
|
||||||
for !*settings.KeepNameserver && *settings.ServerEnabled {
|
settings := l.GetSettings()
|
||||||
var err error
|
var err error
|
||||||
runError, err = l.setupServer(ctx)
|
runError, err = l.setupServer(ctx, settings)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
l.backoffTime = defaultBackoffTime
|
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)
|
err = l.updateFiles(ctx, settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -58,16 +52,9 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
l.logAndWait(ctx, err)
|
l.logAndWait(ctx, err)
|
||||||
settings = l.GetSettings()
|
|
||||||
}
|
}
|
||||||
l.signalOrSetStatus(constants.Running)
|
l.signalOrSetStatus(constants.Running)
|
||||||
|
|
||||||
settings = l.GetSettings()
|
|
||||||
if !*settings.KeepNameserver && !*settings.ServerEnabled {
|
|
||||||
const fallback = false
|
|
||||||
l.useUnencryptedDNS(fallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
l.userTrigger = false
|
l.userTrigger = false
|
||||||
|
|
||||||
exitLoop := l.runWait(ctx, runError)
|
exitLoop := l.runWait(ctx, runError)
|
||||||
@@ -81,21 +68,15 @@ func (l *Loop) runWait(ctx context.Context, runError <-chan error) (exitLoop boo
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
settings := l.GetSettings()
|
l.stopServer()
|
||||||
if !*settings.KeepNameserver && *settings.ServerEnabled {
|
// TODO revert OS and Go nameserver when exiting
|
||||||
l.stopServer()
|
|
||||||
// TODO revert OS and Go nameserver when exiting
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
case <-l.stop:
|
case <-l.stop:
|
||||||
l.userTrigger = true
|
l.userTrigger = true
|
||||||
l.logger.Info("stopping")
|
l.logger.Info("stopping")
|
||||||
settings := l.GetSettings()
|
const fallback = false
|
||||||
if !*settings.KeepNameserver && *settings.ServerEnabled {
|
l.useUnencryptedDNS(fallback)
|
||||||
const fallback = false
|
l.stopServer()
|
||||||
l.useUnencryptedDNS(fallback)
|
|
||||||
l.stopServer()
|
|
||||||
}
|
|
||||||
l.stopped <- struct{}{}
|
l.stopped <- struct{}{}
|
||||||
case <-l.start:
|
case <-l.start:
|
||||||
l.userTrigger = true
|
l.userTrigger = true
|
||||||
|
|||||||
+54
-18
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/qdm12/dns/v2/pkg/doh"
|
"github.com/qdm12/dns/v2/pkg/doh"
|
||||||
"github.com/qdm12/dns/v2/pkg/dot"
|
"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)
|
return l.state.SetSettings(ctx, settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildServerSettings(settings settings.DNS,
|
func buildServerSettings(userSettings settings.DNS,
|
||||||
filter *mapfilter.Filter, localResolvers []netip.Addr,
|
filter *mapfilter.Filter, localResolvers []netip.Addr,
|
||||||
logger Logger) (
|
localSubnets []netip.Prefix, logger Logger) (
|
||||||
serverSettings server.Settings, err error,
|
serverSettings server.Settings, err error,
|
||||||
) {
|
) {
|
||||||
serverSettings.Logger = logger
|
serverSettings.Logger = logger
|
||||||
|
|
||||||
providersData := provider.NewProviders()
|
upstreamResolvers := buildProviders(userSettings, localSubnets, logger)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ipVersion := "ipv4"
|
ipVersion := "ipv4"
|
||||||
if *settings.IPv6 {
|
if *userSettings.IPv6 {
|
||||||
ipVersion = "ipv6"
|
ipVersion = "ipv6"
|
||||||
}
|
}
|
||||||
|
|
||||||
var dialer server.Dialer
|
var dialer server.Dialer
|
||||||
switch settings.UpstreamType {
|
switch userSettings.UpstreamType {
|
||||||
case "dot":
|
case settings.DNSUpstreamTypeDot:
|
||||||
dialerSettings := dot.Settings{
|
dialerSettings := dot.Settings{
|
||||||
UpstreamResolvers: upstreamResolvers,
|
UpstreamResolvers: upstreamResolvers,
|
||||||
IPVersion: ipVersion,
|
IPVersion: ipVersion,
|
||||||
@@ -59,7 +52,7 @@ func buildServerSettings(settings settings.DNS,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return server.Settings{}, fmt.Errorf("creating DNS over TLS dialer: %w", err)
|
return server.Settings{}, fmt.Errorf("creating DNS over TLS dialer: %w", err)
|
||||||
}
|
}
|
||||||
case "doh":
|
case settings.DNSUpstreamTypeDoh:
|
||||||
dialerSettings := doh.Settings{
|
dialerSettings := doh.Settings{
|
||||||
UpstreamResolvers: upstreamResolvers,
|
UpstreamResolvers: upstreamResolvers,
|
||||||
IPVersion: ipVersion,
|
IPVersion: ipVersion,
|
||||||
@@ -68,7 +61,7 @@ func buildServerSettings(settings settings.DNS,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return server.Settings{}, fmt.Errorf("creating DNS over HTTPS dialer: %w", err)
|
return server.Settings{}, fmt.Errorf("creating DNS over HTTPS dialer: %w", err)
|
||||||
}
|
}
|
||||||
case "plain":
|
case settings.DNSUpstreamTypePlain:
|
||||||
dialerSettings := plain.Settings{
|
dialerSettings := plain.Settings{
|
||||||
UpstreamResolvers: upstreamResolvers,
|
UpstreamResolvers: upstreamResolvers,
|
||||||
IPVersion: ipVersion,
|
IPVersion: ipVersion,
|
||||||
@@ -78,11 +71,11 @@ func buildServerSettings(settings settings.DNS,
|
|||||||
return server.Settings{}, fmt.Errorf("creating plain DNS dialer: %w", err)
|
return server.Settings{}, fmt.Errorf("creating plain DNS dialer: %w", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown upstream type: " + settings.UpstreamType)
|
panic("unknown upstream type: " + userSettings.UpstreamType)
|
||||||
}
|
}
|
||||||
serverSettings.Dialer = dialer
|
serverSettings.Dialer = dialer
|
||||||
|
|
||||||
if *settings.Caching {
|
if *userSettings.Caching {
|
||||||
lruCache, err := lru.New(lru.Settings{})
|
lruCache, err := lru.New(lru.Settings{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return server.Settings{}, fmt.Errorf("creating LRU cache: %w", err)
|
return server.Settings{}, fmt.Errorf("creating LRU cache: %w", err)
|
||||||
@@ -123,3 +116,46 @@ func buildServerSettings(settings settings.DNS,
|
|||||||
|
|
||||||
return serverSettings, nil
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
|
||||||
|
|
||||||
"github.com/qdm12/dns/v2/pkg/check"
|
"github.com/qdm12/dns/v2/pkg/check"
|
||||||
"github.com/qdm12/dns/v2/pkg/middlewares/filter/update"
|
"github.com/qdm12/dns/v2/pkg/middlewares/filter/update"
|
||||||
"github.com/qdm12/dns/v2/pkg/nameserver"
|
"github.com/qdm12/dns/v2/pkg/nameserver"
|
||||||
"github.com/qdm12/dns/v2/pkg/server"
|
"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) {
|
func (l *Loop) setupServer(ctx context.Context, settings settings.DNS) (runError <-chan error, err error) {
|
||||||
settings := l.GetSettings()
|
|
||||||
var updateSettings update.Settings
|
var updateSettings update.Settings
|
||||||
updateSettings.SetRebindingProtectionExempt(settings.Blacklist.RebindingProtectionExemptHostnames)
|
updateSettings.SetRebindingProtectionExempt(settings.Blacklist.RebindingProtectionExemptHostnames)
|
||||||
err = l.filter.Update(updateSettings)
|
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)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("building server settings: %w", err)
|
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
|
l.server = server
|
||||||
|
|
||||||
// use internal DNS server
|
// use internal DNS server
|
||||||
const defaultDNSPort = 53
|
nameserver.UseDNSInternally(nameserver.SettingsInternalDNS{})
|
||||||
nameserver.UseDNSInternally(nameserver.SettingsInternalDNS{
|
|
||||||
AddrPort: netip.AddrPortFrom(settings.ServerAddress, defaultDNSPort),
|
|
||||||
})
|
|
||||||
err = nameserver.UseDNSSystemWide(nameserver.SettingsSystemDNS{
|
err = nameserver.UseDNSSystemWide(nameserver.SettingsSystemDNS{
|
||||||
IPs: []netip.Addr{settings.ServerAddress},
|
|
||||||
ResolvPath: l.resolvConf,
|
ResolvPath: l.resolvConf,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ func (s *State) SetSettings(ctx context.Context, settings settings.DNS) (
|
|||||||
|
|
||||||
// Restart
|
// Restart
|
||||||
_, _ = s.statusApplier.ApplyStatus(ctx, constants.Stopped)
|
_, _ = 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
|
return outcome
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/dns/v2/pkg/check"
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/netlink"
|
"github.com/qdm12/gluetun/internal/netlink"
|
||||||
"github.com/qdm12/gluetun/internal/pmtud"
|
"github.com/qdm12/gluetun/internal/pmtud"
|
||||||
@@ -91,14 +90,7 @@ func (l *Loop) onTunnelUp(ctx, loopCtx context.Context, data tunnelUpData) {
|
|||||||
// to start monitoring health and auto-healing.
|
// to start monitoring health and auto-healing.
|
||||||
go l.collectHealthErrors(ctx, loopCtx, healthErrCh)
|
go l.collectHealthErrors(ctx, loopCtx, healthErrCh)
|
||||||
|
|
||||||
if *l.dnsLooper.GetSettings().ServerEnabled {
|
_, _ = l.dnsLooper.ApplyStatus(ctx, constants.Running)
|
||||||
_, _ = l.dnsLooper.ApplyStatus(ctx, constants.Running)
|
|
||||||
} else {
|
|
||||||
err := check.WaitForDNS(ctx, check.Settings{})
|
|
||||||
if err != nil {
|
|
||||||
l.logger.Error("waiting for DNS to be ready: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = l.publicip.RunOnce(ctx)
|
err = l.publicip.RunOnce(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user