netconfigd: write /tmp/resolv.conf only once, do not clobber

This fixes tailscale name resolution breaking again and again.
This commit is contained in:
Michael Stapelberg 2025-01-26 10:16:38 +01:00
parent 07325dde93
commit 0f75b1cbef

View File

@ -30,7 +30,6 @@ import (
"github.com/google/nftables" "github.com/google/nftables"
"github.com/google/nftables/binaryutil" "github.com/google/nftables/binaryutil"
"github.com/google/nftables/expr" "github.com/google/nftables/expr"
"github.com/google/renameio"
"github.com/mdlayher/ethtool" "github.com/mdlayher/ethtool"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
@ -436,6 +435,34 @@ func applyInterfaceFEC(details InterfaceDetails) error {
return nil return nil
} }
func createResolvConfIfMissing(root, contents string) error {
fn := filepath.Join(root, "tmp", "resolv.conf")
// Explicitly check for the file's existance
// just so that we can avoid printing an error
// in the normal case (file exists).
if _, err := os.Stat(fn); err == nil {
return nil // file already exists, do not overwrite
} else if !os.IsNotExist(err) {
return err // unexpected error
}
// /tmp/resolv.conf does not exist yet, create it.
// This is os.WriteFile, but with O_EXCL set
// so that we do not accidentally clobber the file
// in case another process (e.g. tailscaled) just wrote it.
f, err := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0644)
if err != nil {
return err
}
_, err = f.Write([]byte(contents))
if err1 := f.Close(); err1 != nil && err == nil {
err = err1
}
return err
}
func applyInterfaces(dir, root string, cfg InterfaceConfig) error { func applyInterfaces(dir, root string, cfg InterfaceConfig) error {
byName := make(map[string]InterfaceDetails) byName := make(map[string]InterfaceDetails)
byHardwareAddr := make(map[string]InterfaceDetails) byHardwareAddr := make(map[string]InterfaceDetails)
@ -527,12 +554,9 @@ func applyInterfaces(dir, root string, cfg InterfaceConfig) error {
} }
if details.Name == "lan0" { if details.Name == "lan0" {
b := []byte("nameserver " + addr.IP.String() + "\n") // Use dnsd for the system's own DNS resolution.
fn := filepath.Join(root, "tmp", "resolv.conf") resolvConf := "nameserver " + addr.IP.String() + "\n"
if err := os.Remove(fn); err != nil && !os.IsNotExist(err) { if err := createResolvConfIfMissing(root, resolvConf); err != nil {
return err
}
if err := renameio.WriteFile(fn, b, 0644); err != nil {
return err return err
} }
} }