net/dns/resolvd: prevent overwriting our backup resolv.conf (#12360)

When SetDNS is called multiple times, such as on start up, the current
implementation will create backupConf, and then subsequent calls will
overwrite our backup with the last generated resolv.conf file. Guard
against this by only copying the backupConf the first time.

Write the sentinel comments that allow us to check whether we "own" the
resolv.conf as resolvconffile does. Also do some clean up of the resolvd
nameserver entries and whitespace, to enable a follow up commit to
transition to writing the config with resolvconffile instead of open
coding it.

Fixes #12360

Signed-off-by: Kyle McMartin <jkkm@jkkm.org>
pull/15871/head
Kyle McMartin 7 months ago
parent 32ce1bdb48
commit bd29c4ab40

@ -38,11 +38,31 @@ func (m *resolvdManager) SetDNS(config OSConfig) error {
m.ifName,
}
origResolv, err := m.readAndCopy(resolvConf, backupConf, 0644)
// first, read in the resolvConf
origResolv, err := m.fs.ReadFile(resolvConf)
if err != nil {
return err
}
newResolvConf := removeSearchLines(origResolv)
// search for our sentinel in resolvConf, if it's not present
// it's our first call to SetDNS, and we should make backupConf
resolvConfOwned := bytes.Contains(origResolv, []byte("generated by tailscale"))
if !resolvConfOwned {
_, err = m.fs.Stat(backupConf)
if err != nil && os.IsNotExist(err) {
_, err = m.readAndCopy(resolvConf, backupConf, 0644)
if err != nil {
return err
}
}
}
// remove resolvd nameservers and search lines
origResolv = removeSearchLines(origResolv)
origResolv = removeResolvdNameserverLines(origResolv)
// and clean up whitespace
removeBlanks := regexp.MustCompile(`(?m)^\s*\n`)
origResolv = removeBlanks.ReplaceAll(origResolv, []byte(""))
for _, ns := range config.Nameservers {
args = append(args, ns.String())
@ -55,6 +75,15 @@ func (m *resolvdManager) SetDNS(config OSConfig) error {
newSearch = append(newSearch, s.WithoutTrailingDot())
}
var resolvConfHeader = []byte("")
if !resolvConfOwned {
// if we don't have a header, insert one
resolvConfHeader = []byte(
"# resolv.conf(5) file generated by tailscale\n" +
"# For more info, see https://tailscale.com/s/resolvconf-overwrite\n" +
"# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN\n\n")
}
newResolvConf := append(resolvConfHeader, origResolv...)
if len(newSearch) > 1 {
newResolvConf = append(newResolvConf, []byte(strings.Join(newSearch, " "))...)
newResolvConf = append(newResolvConf, '\n')
@ -123,6 +152,11 @@ func (m resolvdManager) readResolvConf() (config OSConfig, err error) {
}, nil
}
func removeResolvdNameserverLines(orig []byte) []byte {
re := regexp.MustCompile(`(?m)^nameserver\s+[^\s]+\s+#\s+resolvd:.*$`)
return re.ReplaceAll(orig, []byte(""))
}
func removeSearchLines(orig []byte) []byte {
re := regexp.MustCompile(`(?ms)^search\s+.+$`)
return re.ReplaceAll(orig, []byte(""))

Loading…
Cancel
Save