Unifying DNS from /etc/resolv.conf function

As part of v1.4.0 release, reading DNS from /etc/resolv.conf file is
only available for Macos. However, there's no reason to prevent this
function from working on other *nix systems.

This commit unify the function to *nix, so it could be added as DNS
source for Linux and Freebsd.
This commit is contained in:
Cuong Manh Le
2025-04-15 18:51:56 +07:00
committed by Cuong Manh Le
parent 0c2cc00c4f
commit c06c8aa859
6 changed files with 63 additions and 53 deletions

View File

@@ -10,7 +10,7 @@ import (
)
func dnsFns() []dnsFn {
return []dnsFn{dnsFromRIB}
return []dnsFn{dnsFromResolvConf, dnsFromRIB}
}
func dnsFromRIB() []string {

View File

@@ -16,58 +16,12 @@ import (
"time"
"tailscale.com/net/netmon"
"github.com/Control-D-Inc/ctrld/internal/resolvconffile"
)
func dnsFns() []dnsFn {
return []dnsFn{dnsFromResolvConf, getDNSFromScutil, getAllDHCPNameservers}
}
// dnsFromResolvConf reads nameservers from /etc/resolv.conf
func dnsFromResolvConf() []string {
const (
maxRetries = 10
retryInterval = 100 * time.Millisecond
)
regularIPs, loopbackIPs, _ := netmon.LocalAddresses()
var dns []string
for attempt := 0; attempt < maxRetries; attempt++ {
if attempt > 0 {
time.Sleep(retryInterval)
}
nss := resolvconffile.NameServers("")
var localDNS []string
seen := make(map[string]bool)
for _, ns := range nss {
if ip := net.ParseIP(ns); ip != nil {
// skip loopback IPs
for _, v := range slices.Concat(regularIPs, loopbackIPs) {
ipStr := v.String()
if ip.String() == ipStr {
continue
}
}
if !seen[ip.String()] {
seen[ip.String()] = true
localDNS = append(localDNS, ip.String())
}
}
}
// If we successfully read the file and found nameservers, return them
if len(localDNS) > 0 {
return localDNS
}
}
return dns
}
func getDNSFromScutil() []string {
logger := *ProxyLogger.Load()

View File

@@ -17,7 +17,7 @@ const (
)
func dnsFns() []dnsFn {
return []dnsFn{dns4, dns6, dnsFromSystemdResolver}
return []dnsFn{dnsFromResolvConf, dns4, dns6, dnsFromSystemdResolver}
}
func dns4() []string {

View File

@@ -2,8 +2,63 @@
package ctrld
import "github.com/Control-D-Inc/ctrld/internal/resolvconffile"
import (
"net"
"slices"
"time"
func nameserversFromResolvconf() []string {
"tailscale.com/net/netmon"
"github.com/Control-D-Inc/ctrld/internal/resolvconffile"
)
// currentNameserversFromResolvconf returns the current nameservers set from /etc/resolv.conf file.
func currentNameserversFromResolvconf() []string {
return resolvconffile.NameServers("")
}
// dnsFromResolvConf reads usable nameservers from /etc/resolv.conf file.
// A nameserver is usable if it's not one of current machine's IP addresses
// and loopback IP addresses.
func dnsFromResolvConf() []string {
const (
maxRetries = 10
retryInterval = 100 * time.Millisecond
)
regularIPs, loopbackIPs, _ := netmon.LocalAddresses()
var dns []string
for attempt := 0; attempt < maxRetries; attempt++ {
if attempt > 0 {
time.Sleep(retryInterval)
}
nss := resolvconffile.NameServers("")
var localDNS []string
seen := make(map[string]bool)
for _, ns := range nss {
if ip := net.ParseIP(ns); ip != nil {
// skip loopback IPs
for _, v := range slices.Concat(regularIPs, loopbackIPs) {
ipStr := v.String()
if ip.String() == ipStr {
continue
}
}
if !seen[ip.String()] {
seen[ip.String()] = true
localDNS = append(localDNS, ip.String())
}
}
}
// If we successfully read the file and found nameservers, return them
if len(localDNS) > 0 {
return localDNS
}
}
return dns
}

View File

@@ -158,7 +158,7 @@ func getDNSServers(ctx context.Context) ([]string, error) {
0, // DomainGuid - not needed
0, // SiteName - not needed
uintptr(flags), // Flags
uintptr(unsafe.Pointer(&info))) // DomainControllerInfo - output
uintptr(unsafe.Pointer(&info))) // DomainControllerInfo - output
if ret != 0 {
switch ret {
@@ -330,7 +330,8 @@ func getDNSServers(ctx context.Context) ([]string, error) {
return ns, nil
}
func nameserversFromResolvconf() []string {
// currentNameserversFromResolvconf returns a nil slice of strings.
func currentNameserversFromResolvconf() []string {
return nil
}

View File

@@ -584,7 +584,7 @@ func NewPrivateResolver() Resolver {
}
nss := *or.lanServers.Load()
resolverMutex.Unlock()
resolveConfNss := nameserversFromResolvconf()
resolveConfNss := currentNameserversFromResolvconf()
localRfc1918Addrs := Rfc1918Addresses()
n := 0
for _, ns := range nss {