diff --git a/client/internal/dns/file_linux.go b/client/internal/dns/file_linux.go index ad6e3a37f..b9a7f4804 100644 --- a/client/internal/dns/file_linux.go +++ b/client/internal/dns/file_linux.go @@ -44,7 +44,7 @@ func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error { return fmt.Errorf("unable to configure DNS for this peer using file manager without a Primary nameserver group. Restoring the original file return err: %s", err) } } - return fmt.Errorf("unable to configure DNS for this peer using file manager without a Primary nameserver group") + return fmt.Errorf("unable to configure DNS for this peer using file manager without a nameserver group with all domains configured") } managerType, err := getOSDNSManagerType() if err != nil { @@ -92,7 +92,7 @@ func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error { } return err } - log.Infof("created a NetBird managed %s file with your DNS settings", defaultResolvConfPath) + log.Infof("created a NetBird managed %s file with your DNS settings. Added %d search domains. Search list: %s", defaultResolvConfPath, appendedDomains, searchDomains) return nil } diff --git a/client/internal/dns/host_linux.go b/client/internal/dns/host_linux.go index 368c7e35e..e411280cc 100644 --- a/client/internal/dns/host_linux.go +++ b/client/internal/dns/host_linux.go @@ -35,6 +35,8 @@ func newHostManager(wgInterface *iface.WGIface) (hostManager, error) { return newNetworkManagerDbusConfigurator(wgInterface) case systemdManager: return newSystemdDbusConfigurator(wgInterface) + case resolvConfManager: + return newResolvConfConfigurator(wgInterface) default: return newFileConfigurator() } diff --git a/client/internal/dns/resolvconf_linux.go b/client/internal/dns/resolvconf_linux.go new file mode 100644 index 000000000..7bd4511ac --- /dev/null +++ b/client/internal/dns/resolvconf_linux.go @@ -0,0 +1,84 @@ +package dns + +import ( + "fmt" + "github.com/netbirdio/netbird/iface" + log "github.com/sirupsen/logrus" + "os/exec" + "strings" +) + +const resolvconfCommand = "resolvconf" + +type resolvconf struct { + ifaceName string +} + +func newResolvConfConfigurator(wgInterface *iface.WGIface) (hostManager, error) { + return &resolvconf{ + ifaceName: wgInterface.GetName(), + }, nil +} + +func (r *resolvconf) applyDNSConfig(config hostDNSConfig) error { + var err error + if !config.routeAll { + err = r.restoreHostDNS() + if err != nil { + log.Error(err) + } + return fmt.Errorf("unable to configure DNS for this peer using resolvconf manager without a nameserver group with all domains configured") + } + + var searchDomains string + appendedDomains := 0 + for _, dConf := range config.domains { + if dConf.matchOnly { + continue + } + + if appendedDomains >= fileMaxNumberOfSearchDomains { + // lets log all skipped domains + log.Infof("already appended %d domains to search list. Skipping append of %s domain", fileMaxNumberOfSearchDomains, dConf.domain) + continue + } + + if fileSearchLineBeginCharCount+len(searchDomains) > fileMaxLineCharsLimit { + // lets log all skipped domains + log.Infof("search list line is larger than %d characters. Skipping append of %s domain", fileMaxLineCharsLimit, dConf.domain) + continue + } + + searchDomains += " " + dConf.domain + appendedDomains++ + } + + content := fmt.Sprintf(fileGeneratedResolvConfContentFormat, fileDefaultResolvConfBackupLocation, config.serverIP, searchDomains) + + err = r.applyConfig(content) + if err != nil { + return err + } + + log.Infof("added %d search domains. Search list: %s", appendedDomains, searchDomains) + return nil +} + +func (r *resolvconf) restoreHostDNS() error { + cmd := exec.Command(resolvconfCommand, "-f", "-d", r.ifaceName) + _, err := cmd.Output() + if err != nil { + return fmt.Errorf("got an error while removing resolvconf configuration for %s interface, error: %s", r.ifaceName, err) + } + return nil +} + +func (r *resolvconf) applyConfig(content string) error { + cmd := exec.Command(resolvconfCommand, "-x", "-a", r.ifaceName) + cmd.Stdin = strings.NewReader(content) + _, err := cmd.Output() + if err != nil { + return fmt.Errorf("got an error while appying resolvconf configuration for %s interface, error: %s", r.ifaceName, err) + } + return nil +}