From d17849461cf82f52e8c2d13d958c7a871d8b3714 Mon Sep 17 00:00:00 2001 From: Denton Gentry Date: Sun, 17 Jul 2022 10:05:36 -0700 Subject: [PATCH] ipn/{ipnserver,ipnlocal}: support incoming Taildrop on QNAP Signed-off-by: Denton Gentry --- ipn/ipnlocal/local.go | 8 ++++---- ipn/ipnserver/server.go | 26 +++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 10cc0cf8e..008f121e4 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -174,11 +174,11 @@ type LocalBackend struct { // same as the Network Extension lifetime and we can thus avoid // double-copying files by writing them to the right location // immediately. - // It's also used on Synology & TrueNAS, but in that case DoFinalRename - // is also set true, which moves the *.partial file to its final - // name on completion. + // It's also used on several NAS platforms (Synology, TrueNAS, etc) + // but in that case DoFinalRename is also set true, which moves the + // *.partial file to its final name on completion. directFileRoot string - directFileDoFinalRename bool // false on macOS, true on Synology & TrueNAS + directFileDoFinalRename bool // false on macOS, true on several NAS platforms // statusLock must be held before calling statusChanged.Wait() or // statusChanged.Broadcast(). diff --git a/ipn/ipnserver/server.go b/ipn/ipnserver/server.go index cd4094fef..a430f750f 100644 --- a/ipn/ipnserver/server.go +++ b/ipn/ipnserver/server.go @@ -772,7 +772,7 @@ func New(logf logger.Logf, logid string, store ipn.StateStore, eng wgengine.Engi dg := distro.Get() switch dg { - case distro.Synology, distro.TrueNAS: + case distro.Synology, distro.TrueNAS, distro.QNAP: // See if they have a "Taildrop" share. // See https://github.com/tailscale/tailscale/issues/2179#issuecomment-982821319 path, err := findTaildropDir(dg) @@ -1123,6 +1123,8 @@ func findTaildropDir(dg distro.Distro) (string, error) { return findSynologyTaildropDir(name) case distro.TrueNAS: return findTrueNASTaildropDir(name) + case distro.QNAP: + return findQnapTaildropDir(name) } return "", fmt.Errorf("%s is an unsupported distro for Taildrop dir", dg) } @@ -1163,6 +1165,28 @@ func findTrueNASTaildropDir(name string) (dir string, err error) { return "", fmt.Errorf("shared folder %q not found", name) } +// findQnapTaildropDir checks if a Shared Folder named "Taildrop" exists. +func findQnapTaildropDir(name string) (string, error) { + dir := fmt.Sprintf("/share/%s", name) + fi, err := os.Stat(dir) + if err != nil { + return "", fmt.Errorf("shared folder %q not found", name) + } + if fi.IsDir() { + return dir, nil + } + + // share/Taildrop is usually a symlink to CACHEDEV1_DATA/Taildrop/ or some such. + fullpath, err := filepath.EvalSymlinks(dir) + if err != nil { + return "", fmt.Errorf("symlink to shared folder %q not found", name) + } + if fi, err = os.Stat(fullpath); err == nil && fi.IsDir() { + return dir, nil // return the symlink, how QNAP set it up + } + return "", fmt.Errorf("shared folder %q not found", name) +} + func loadExtraEnv() (env []string, err error) { if runtime.GOOS != "windows" { return nil, nil