ipn/{ipnserver,ipnlocal}: support incoming Taildrop on TrueNAS

Signed-off-by: Todd Neal <todd@tneal.org>
This commit is contained in:
Todd Neal 2021-12-06 22:33:45 -06:00 committed by Brad Fitzpatrick
parent ffb16cdffb
commit c18dc57861
2 changed files with 46 additions and 9 deletions

View File

@ -142,11 +142,11 @@ type LocalBackend struct {
// same as the Network Extension lifetime and we can thus avoid // same as the Network Extension lifetime and we can thus avoid
// double-copying files by writing them to the right location // double-copying files by writing them to the right location
// immediately. // immediately.
// It's also used on Synology, but in that case DoFinalRename is // It's also used on Synology & TrueNAS, but in that case DoFinalRename
// also set true, which moves the *.partial file to its final // is also set true, which moves the *.partial file to its final
// name on completion. // name on completion.
directFileRoot string directFileRoot string
directFileDoFinalRename bool // false on macOS, true on Synology directFileDoFinalRename bool // false on macOS, true on Synology & TrueNAS
// statusLock must be held before calling statusChanged.Wait() or // statusLock must be held before calling statusChanged.Wait() or
// statusChanged.Broadcast(). // statusChanged.Broadcast().

View File

@ -759,17 +759,21 @@ func New(logf logger.Logf, logid string, store ipn.StateStore, eng wgengine.Engi
b.SetDecompressor(func() (controlclient.Decompressor, error) { b.SetDecompressor(func() (controlclient.Decompressor, error) {
return smallzstd.NewDecoder(nil) return smallzstd.NewDecoder(nil)
}) })
if distro.Get() == distro.Synology {
dg := distro.Get()
switch dg {
case distro.Synology, distro.TrueNAS:
// See if they have a "Taildrop" share. // See if they have a "Taildrop" share.
// See https://github.com/tailscale/tailscale/issues/2179#issuecomment-982821319 // See https://github.com/tailscale/tailscale/issues/2179#issuecomment-982821319
path, err := findSynologyTaildropDir() path, err := findTaildropDir(dg)
if err != nil { if err != nil {
logf("Synology Taildrop support: %v", err) logf("%s Taildrop support: %v", dg, err)
} else { } else {
logf("Synology Taildrop: using %v", path) logf("%s Taildrop: using %v", dg, path)
b.SetDirectFileRoot(path) b.SetDirectFileRoot(path)
b.SetDirectFileDoFinalRename(true) b.SetDirectFileDoFinalRename(true)
} }
} }
if opts.AutostartStateKey == "" { if opts.AutostartStateKey == "" {
@ -1127,11 +1131,21 @@ func (ln *listenerWithReadyConn) Accept() (net.Conn, error) {
return ln.Listener.Accept() return ln.Listener.Accept()
} }
func findTaildropDir(dg distro.Distro) (string, error) {
const name = "Taildrop"
switch dg {
case distro.Synology:
return findSynologyTaildropDir(name)
case distro.TrueNAS:
return findTrueNASTaildropDir(name)
}
return "", fmt.Errorf("%s is an unsupported distro for Taildrop dir", dg)
}
// findSynologyTaildropDir looks for the first volume containing a // findSynologyTaildropDir looks for the first volume containing a
// "Taildrop" directory. We'd run "synoshare --get Taildrop" command // "Taildrop" directory. We'd run "synoshare --get Taildrop" command
// but on DSM7 at least, we lack permissions to run that. // but on DSM7 at least, we lack permissions to run that.
func findSynologyTaildropDir() (dir string, err error) { func findSynologyTaildropDir(name string) (dir string, err error) {
const name = "Taildrop"
for i := 1; i <= 16; i++ { for i := 1; i <= 16; i++ {
dir = fmt.Sprintf("/volume%v/%s", i, name) dir = fmt.Sprintf("/volume%v/%s", i, name)
if fi, err := os.Stat(dir); err == nil && fi.IsDir() { if fi, err := os.Stat(dir); err == nil && fi.IsDir() {
@ -1140,3 +1154,26 @@ func findSynologyTaildropDir() (dir string, err error) {
} }
return "", fmt.Errorf("shared folder %q not found", name) return "", fmt.Errorf("shared folder %q not found", name)
} }
// findTrueNASTaildropDir returns the first matching directory of
// /mnt/{name} or /mnt/*/{name}
func findTrueNASTaildropDir(name string) (dir string, err error) {
// If we're running in a jail, a mount point could just be added at /mnt/Taildrop
dir = fmt.Sprintf("/mnt/%s", name)
if fi, err := os.Stat(dir); err == nil && fi.IsDir() {
return dir, nil
}
// but if running on the host, it may be something like /mnt/Primary/Taildrop
fis, err := ioutil.ReadDir("/mnt")
if err != nil {
return "", fmt.Errorf("error reading /mnt: %w", err)
}
for _, fi := range fis {
dir = fmt.Sprintf("/mnt/%s/%s", fi.Name(), name)
if fi, err := os.Stat(dir); err == nil && fi.IsDir() {
return dir, nil
}
}
return "", fmt.Errorf("shared folder %q not found", name)
}