|
|
|
@ -8,8 +8,10 @@ import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"crypto/rand"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"io/fs"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"os"
|
|
|
|
|
"os/exec"
|
|
|
|
@ -22,6 +24,7 @@ import (
|
|
|
|
|
"tailscale.com/net/dns/resolvconffile"
|
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
|
"tailscale.com/util/dnsname"
|
|
|
|
|
"tailscale.com/version/distro"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
@ -245,28 +248,42 @@ func (m *directManager) rename(old, new string) error {
|
|
|
|
|
if err == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if runtime.GOOS == "linux" && distro.Get() == distro.Synology {
|
|
|
|
|
// Fail fast. The fallback case below won't work anyway.
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
m.logf("rename of %q to %q failed (%v), falling back to copy+delete", old, new, err)
|
|
|
|
|
m.renameBroken = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bs, err := m.fs.ReadFile(old)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("reading %q to rename: %v", old, err)
|
|
|
|
|
return fmt.Errorf("reading %q to rename: %w", old, err)
|
|
|
|
|
}
|
|
|
|
|
if err := m.fs.WriteFile(new, bs, 0644); err != nil {
|
|
|
|
|
return fmt.Errorf("writing to %q in rename of %q: %v", new, old, err)
|
|
|
|
|
return fmt.Errorf("writing to %q in rename of %q: %w", new, old, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := m.fs.Remove(old); err != nil {
|
|
|
|
|
err2 := m.fs.Truncate(old)
|
|
|
|
|
if err2 != nil {
|
|
|
|
|
return fmt.Errorf("remove of %q failed (%v) and so did truncate: %v", old, err, err2)
|
|
|
|
|
return fmt.Errorf("remove of %q failed (%w) and so did truncate: %v", old, err, err2)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *directManager) SetDNS(config OSConfig) (err error) {
|
|
|
|
|
defer func() {
|
|
|
|
|
if err != nil && errors.Is(err, fs.ErrPermission) && runtime.GOOS == "linux" &&
|
|
|
|
|
distro.Get() == distro.Synology && os.Geteuid() != 0 {
|
|
|
|
|
// On Synology (notably DSM7 where we don't run as root), ignore all
|
|
|
|
|
// DNS configuration errors for now. We don't have permission.
|
|
|
|
|
// See https://github.com/tailscale/tailscale/issues/4017
|
|
|
|
|
m.logf("ignoring SetDNS permission error on Synology (Issue 4017); was: %v", err)
|
|
|
|
|
err = nil
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
var changed bool
|
|
|
|
|
if config.IsZero() {
|
|
|
|
|
changed, err = m.restoreBackup()
|
|
|
|
|