mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 00:01:40 +01:00 
			
		
		
		
	During resolv.conf update, old 'search' lines are cleared but '\n' is not deleted, leaving behind a new blank line on every update. This adds 's' flag to regexp, so '\n' is included in the match and deleted when old lines are cleared. Also, insert missing `\n` when updated 'search' line is appended to resolv.conf. Signed-off-by: Renato Aguiar <renato@renatoaguiar.net>
		
			
				
	
	
		
			130 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| //go:build openbsd
 | |
| 
 | |
| package dns
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"os"
 | |
| 	"os/exec"
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| 
 | |
| 	"tailscale.com/net/dns/resolvconffile"
 | |
| 	"tailscale.com/types/logger"
 | |
| )
 | |
| 
 | |
| func newResolvdManager(logf logger.Logf, interfaceName string) (*resolvdManager, error) {
 | |
| 	return &resolvdManager{
 | |
| 		logf:   logf,
 | |
| 		ifName: interfaceName,
 | |
| 		fs:     directFS{},
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // resolvdManager is an OSConfigurator which uses route(1) to teach OpenBSD's
 | |
| // resolvd(8) about DNS servers.
 | |
| type resolvdManager struct {
 | |
| 	logf   logger.Logf
 | |
| 	ifName string
 | |
| 	fs     directFS
 | |
| }
 | |
| 
 | |
| func (m *resolvdManager) SetDNS(config OSConfig) error {
 | |
| 	args := []string{
 | |
| 		"nameserver",
 | |
| 		m.ifName,
 | |
| 	}
 | |
| 
 | |
| 	origResolv, err := m.readAndCopy(resolvConf, backupConf, 0644)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	newResolvConf := removeSearchLines(origResolv)
 | |
| 
 | |
| 	for _, ns := range config.Nameservers {
 | |
| 		args = append(args, ns.String())
 | |
| 	}
 | |
| 
 | |
| 	var newSearch = []string{
 | |
| 		"search",
 | |
| 	}
 | |
| 	for _, s := range config.SearchDomains {
 | |
| 		newSearch = append(newSearch, s.WithoutTrailingDot())
 | |
| 	}
 | |
| 
 | |
| 	if len(newSearch) > 1 {
 | |
| 		newResolvConf = append(newResolvConf, []byte(strings.Join(newSearch, " "))...)
 | |
| 		newResolvConf = append(newResolvConf, '\n')
 | |
| 	}
 | |
| 
 | |
| 	err = m.fs.WriteFile(resolvConf, newResolvConf, 0644)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	cmd := exec.Command("/sbin/route", args...)
 | |
| 	return cmd.Run()
 | |
| }
 | |
| 
 | |
| func (m *resolvdManager) SupportsSplitDNS() bool {
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (m *resolvdManager) GetBaseConfig() (OSConfig, error) {
 | |
| 	cfg, err := m.readResolvConf()
 | |
| 	if err != nil {
 | |
| 		return OSConfig{}, err
 | |
| 	}
 | |
| 
 | |
| 	return cfg, nil
 | |
| }
 | |
| 
 | |
| func (m *resolvdManager) Close() error {
 | |
| 	// resolvd handles teardown of nameservers so we only need to write back the original
 | |
| 	// config and be done.
 | |
| 
 | |
| 	_, err := m.readAndCopy(backupConf, resolvConf, 0644)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return m.fs.Remove(backupConf)
 | |
| }
 | |
| 
 | |
| func (m *resolvdManager) readAndCopy(a, b string, mode os.FileMode) ([]byte, error) {
 | |
| 	orig, err := m.fs.ReadFile(a)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	err = m.fs.WriteFile(b, orig, mode)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return orig, nil
 | |
| }
 | |
| 
 | |
| func (m resolvdManager) readResolvConf() (config OSConfig, err error) {
 | |
| 	b, err := m.fs.ReadFile(resolvConf)
 | |
| 	if err != nil {
 | |
| 		return OSConfig{}, err
 | |
| 	}
 | |
| 
 | |
| 	rconf, err := resolvconffile.Parse(bytes.NewReader(b))
 | |
| 	if err != nil {
 | |
| 		return config, err
 | |
| 	}
 | |
| 	return OSConfig{
 | |
| 		Nameservers:   rconf.Nameservers,
 | |
| 		SearchDomains: rconf.SearchDomains,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| func removeSearchLines(orig []byte) []byte {
 | |
| 	re := regexp.MustCompile(`(?ms)^search\s+.+$`)
 | |
| 	return re.ReplaceAll(orig, []byte(""))
 | |
| }
 |