mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-03 22:18:39 +00:00
Currently, ctrld watches changes to /etc/resolv.conf file, then reverting to the expected settings. However, if /etc/resolv.conf is a symlink, changes made to the target file maynot be seen if it's not under /etc directory. To fix this, just evaluate the /etc/resolv.conf file before watching it.
66 lines
2.0 KiB
Go
66 lines
2.0 KiB
Go
package cli
|
|
|
|
import (
|
|
"net"
|
|
"net/netip"
|
|
"path/filepath"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
)
|
|
|
|
// watchResolvConf watches any changes to /etc/resolv.conf file,
|
|
// and reverting to the original config set by ctrld.
|
|
func watchResolvConf(iface *net.Interface, ns []netip.Addr, setDnsFn func(iface *net.Interface, ns []netip.Addr) error) {
|
|
resolvConfPath := "/etc/resolv.conf"
|
|
// Evaluating symbolics link to watch the target file that /etc/resolv.conf point to.
|
|
if rp, _ := filepath.EvalSymlinks(resolvConfPath); rp != "" {
|
|
resolvConfPath = rp
|
|
}
|
|
mainLog.Load().Debug().Msgf("start watching %s file", resolvConfPath)
|
|
watcher, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
mainLog.Load().Warn().Err(err).Msg("could not create watcher for /etc/resolv.conf")
|
|
return
|
|
}
|
|
defer watcher.Close()
|
|
|
|
// 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).Msgf("could not add %s to watcher list", watchDir)
|
|
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 := setDnsFn(iface, ns); 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")
|
|
}
|
|
}
|
|
}
|