Skip to content

Commit

Permalink
Move repair logic to new sturct
Browse files Browse the repository at this point in the history
  • Loading branch information
pappz committed Jan 23, 2024
1 parent 9d94a01 commit 838632a
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 146 deletions.
158 changes: 16 additions & 142 deletions client/internal/dns/file_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ package dns

import (
"bytes"
"errors"
"fmt"
"os"
"strings"
"sync"

"github.com/illarion/gonotify"
log "github.com/sirupsen/logrus"
)

Expand All @@ -26,16 +23,14 @@ const (
)

type fileConfigurator struct {
originalPerms os.FileMode
inotify *gonotify.Inotify
inotifyWg sync.WaitGroup
inotifyLock sync.Mutex
nbSearchDomains []string
nbNameserverIP string
repair *repair

originalPerms os.FileMode
}

func newFileConfigurator() (hostManager, error) {
fc := &fileConfigurator{}
fc.repair = newRepair(fc.updateConfig)
return fc, nil
}

Expand Down Expand Up @@ -67,31 +62,27 @@ func (f *fileConfigurator) applyDNSConfig(config HostDNSConfig) error {
}
}

f.inotifyLock.Lock()
f.nbSearchDomains = searchDomains(config)
f.nbNameserverIP = config.ServerIP
defer f.inotifyLock.Unlock()
nbSearchDomains := searchDomains(config)
nbNameserverIP := config.ServerIP

resolvConf, err := parseBackupResolvConf()
if err != nil {
log.Error(err)
}

f.stopWatchFileChanges()
f.repair.stopWatchFileChanges()

err = f.updateConfig(resolvConf)
err = f.updateConfig(nbSearchDomains, nbNameserverIP, resolvConf)
if err != nil {
return err
}
f.watchFileChanges()
f.repair.watchFileChanges(nbSearchDomains, nbNameserverIP)
return nil
}

func (f *fileConfigurator) updateConfig(cfg *resolvConf) error {
f.inotifyLock.Lock()
defer f.inotifyLock.Unlock()
searchDomainList := mergeSearchDomains(f.nbSearchDomains, cfg.searchDomains)
nameServers := f.generateNsList(cfg)
func (f *fileConfigurator) updateConfig(nbSearchDomains []string, nbNameserverIP string, cfg *resolvConf) error {
searchDomainList := mergeSearchDomains(nbSearchDomains, cfg.searchDomains)
nameServers := generateNsList(nbNameserverIP, cfg)

buf := prepareResolvConfContent(
searchDomainList,
Expand All @@ -113,7 +104,7 @@ func (f *fileConfigurator) updateConfig(cfg *resolvConf) error {
}

func (f *fileConfigurator) restoreHostDNS() error {
f.stopWatchFileChanges()
f.repair.stopWatchFileChanges()
return f.restore()
}

Expand Down Expand Up @@ -142,134 +133,17 @@ func (f *fileConfigurator) restore() error {
}

// generateNsList generates a list of nameservers from the config and adds the primary nameserver to the beginning of the list
func (f *fileConfigurator) generateNsList(cfg *resolvConf) []string {
func generateNsList(nbNameserverIP string, cfg *resolvConf) []string {
ns := make([]string, 1, len(cfg.nameServers)+1)
ns[0] = f.nbNameserverIP
ns[0] = nbNameserverIP
for _, cfgNs := range cfg.nameServers {
if f.nbNameserverIP != cfgNs {
if nbNameserverIP != cfgNs {
ns = append(ns, cfgNs)
}
}
return ns
}

func (f *fileConfigurator) watchFileChanges() {
if f.inotify != nil {
return
}
inotify, err := gonotify.NewInotify()
if err != nil {
log.Errorf("failed to start inotify watcher for resolv.conf: %s", err)
return
}
f.inotify = inotify

const eventTypes = gonotify.IN_ATTRIB |
gonotify.IN_CREATE |
gonotify.IN_MODIFY |
gonotify.IN_MOVE |
gonotify.IN_CLOSE_WRITE |
gonotify.IN_DELETE

const watchDir = "/etc"
err = f.inotify.AddWatch(watchDir, eventTypes)
if err != nil {
log.Errorf("failed to add inotify watch for resolv.conf: %s", err)
return
}
f.inotifyWg.Add(1)
go func() {
defer f.inotifyWg.Done()
for {
events, err := f.inotify.Read()
if err != nil {
if errors.Is(err, os.ErrClosed) {
log.Infof("inotify closed")
return
}

log.Errorf("failed to read inotify %v", err)
return
}
var match bool
for _, ev := range events {
if ev.Name == defaultResolvConfPath {
match = true
break
}
}
if !match {
continue
}

rConf, err := parseDefaultResolvConf()
if err != nil {
log.Errorf("failed to parse resolv conf: %s", err)
continue
}

if !f.nbParamsAreMissing(rConf) {
log.Debugf("resolv.conf still correct, skip the update")
continue
}
log.Info("broken params in resolv.conf, repair it...")

err = f.inotify.RmWatch(watchDir)
if err != nil {
log.Errorf("failed to rm inotify watch for resolv.conf: %s", err)
}

err = f.updateConfig(rConf)
if err != nil {
log.Errorf("failed to repair resolv.conf: %v", err)
}

err = f.inotify.AddWatch(watchDir, eventTypes)
if err != nil {
log.Errorf("failed to readd inotify watch for resolv.conf: %s", err)
return
}
}
}()
return
}

func (f *fileConfigurator) stopWatchFileChanges() {
if f.inotify == nil {
return
}
err := f.inotify.Close()
if err != nil {
log.Warnf("failed to close resolv.conf inotify: %v", err)
}
f.inotifyWg.Wait()
f.inotify = nil
}

// nbParamsAreMissing checks if the resolv.conf file contains all the parameters that NetBird needs
// check the NetBird related nameserver IP at the first place
// check the NetBird related search domains in the search domains list
func (f *fileConfigurator) nbParamsAreMissing(rConf *resolvConf) bool {
log.Debugf("check parasm: %v, %v", rConf.searchDomains, rConf.nameServers)
if !isContains(f.nbSearchDomains, rConf.searchDomains) {
log.Debugf("broken searchdomains")
return true
}

if len(rConf.nameServers) == 0 {
log.Debugf("empty ns list")
return true
}

if rConf.nameServers[0] != f.nbNameserverIP {
log.Debugf("broken ns")
return true
}

log.Debugf("all good")
return false
}

func prepareResolvConfContent(searchDomains, nameServers, others []string) bytes.Buffer {
var buf bytes.Buffer
buf.WriteString(fileGeneratedResolvConfContentHeaderNextLine)
Expand Down
8 changes: 4 additions & 4 deletions client/internal/dns/file_parser_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"fmt"
"os"
"strings"

log "github.com/sirupsen/logrus"
)

const (
Expand All @@ -18,6 +16,10 @@ type resolvConf struct {
others []string
}

func (r *resolvConf) String() string {
return fmt.Sprintf("search domains: %v, name servers: %v, others: %s", r.searchDomains, r.nameServers, r.others)
}

func parseDefaultResolvConf() (*resolvConf, error) {
return parseResolvConfFile(defaultResolvConfPath)
}
Expand Down Expand Up @@ -68,14 +70,12 @@ func parseResolvConfFile(resolvConfFile string) (*resolvConf, error) {
}

if strings.HasPrefix(line, "search") {
log.Debugf("found search domains: %s", line)
splitLines := strings.Fields(line)
if len(splitLines) < 2 {
continue
}

rconf.searchDomains = splitLines[1:]
log.Debugf("search domains: %s", rconf.searchDomains)
continue
}

Expand Down
Loading

0 comments on commit 838632a

Please sign in to comment.