mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-07-04 01:07:49 +02:00
cmd/cli: watch changes to /etc/resolv.conf
On some routers, change to network may trigger re-rendering /etc/resolv.conf file, causing requests from router itself stop using ctrld. Fixing this by watching changes to /etc/resolv.conf, then revert them.
This commit is contained in:
committed by
Cuong Manh Le
parent
2bebe93e47
commit
a2cb895cdc
+67
-1
@@ -9,10 +9,12 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/insomniacslk/dhcp/dhcpv4/nclient4"
|
"github.com/insomniacslk/dhcp/dhcpv4/nclient4"
|
||||||
"github.com/insomniacslk/dhcp/dhcpv6"
|
"github.com/insomniacslk/dhcp/dhcpv6"
|
||||||
"github.com/insomniacslk/dhcp/dhcpv6/client6"
|
"github.com/insomniacslk/dhcp/dhcpv6/client6"
|
||||||
@@ -23,7 +25,10 @@ import (
|
|||||||
"github.com/Control-D-Inc/ctrld/internal/resolvconffile"
|
"github.com/Control-D-Inc/ctrld/internal/resolvconffile"
|
||||||
)
|
)
|
||||||
|
|
||||||
const resolvConfBackupFailedMsg = "open /etc/resolv.pre-ctrld-backup.conf: read-only file system"
|
const (
|
||||||
|
resolvConfPath = "/etc/resolv.conf"
|
||||||
|
resolvConfBackupFailedMsg = "open /etc/resolv.pre-ctrld-backup.conf: read-only file system"
|
||||||
|
)
|
||||||
|
|
||||||
// allocate loopback ip
|
// allocate loopback ip
|
||||||
// sudo ip a add 127.0.0.2/24 dev lo
|
// sudo ip a add 127.0.0.2/24 dev lo
|
||||||
@@ -64,6 +69,11 @@ func setDNS(iface *net.Interface, nameservers []string) error {
|
|||||||
Nameservers: ns,
|
Nameservers: ns,
|
||||||
SearchDomains: []dnsname.FQDN{},
|
SearchDomains: []dnsname.FQDN{},
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
if r.Mode() == "direct" {
|
||||||
|
go watchResolveConf(osConfig)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
trySystemdResolve := false
|
trySystemdResolve := false
|
||||||
for i := 0; i < maxSetDNSAttempts; i++ {
|
for i := 0; i < maxSetDNSAttempts; i++ {
|
||||||
@@ -299,3 +309,59 @@ func sliceIndex[S ~[]E, E comparable](s S, v E) int {
|
|||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// watchResolveConf watches any changes to /etc/resolv.conf file,
|
||||||
|
// and reverting to the original config set by ctrld.
|
||||||
|
func watchResolveConf(oc dns.OSConfig) {
|
||||||
|
mainLog.Load().Debug().Msg("start watching /etc/resolv.conf file")
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
mainLog.Load().Warn().Err(err).Msg("could not create watcher for /etc/resolv.conf")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We watch /etc instead of /etc/resolv.conf directly,
|
||||||
|
// see: https://github.com/fsnotify/fsnotify#watching-a-file-doesnt-work-well
|
||||||
|
watchDir := filepath.Dir(resolvConfPath)
|
||||||
|
if err := watcher.Add(watchDir); err != nil {
|
||||||
|
mainLog.Load().Warn().Err(err).Msg("could not add /etc/resolv.conf to watcher list")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := dns.NewOSConfigurator(func(format string, args ...any) {}, "lo") // interface name does not matter.
|
||||||
|
if err != nil {
|
||||||
|
mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event, ok := <-watcher.Events:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if event.Name != resolvConfPath { // skip if not /etc/resolv.conf changes.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) {
|
||||||
|
mainLog.Load().Debug().Msg("/etc/resolv.conf changes detected, reverting to ctrld setting")
|
||||||
|
if err := watcher.Remove(watchDir); err != nil {
|
||||||
|
mainLog.Load().Error().Err(err).Msg("failed to pause watcher")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := r.SetDNS(oc); err != nil {
|
||||||
|
mainLog.Load().Error().Err(err).Msg("failed to revert /etc/resolv.conf changes")
|
||||||
|
}
|
||||||
|
if err := watcher.Add(watchDir); err != nil {
|
||||||
|
mainLog.Load().Error().Err(err).Msg("failed to continue running watcher")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case err, ok := <-watcher.Errors:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mainLog.Load().Err(err).Msg("could not get event for /etc/resolv.conf")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user