mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 14:05:39 +00:00
e8cc78b1af
This is step 1 of de-special-casing of Windows and letting the LocalAPI HTTP server start serving immediately, even while the rest of the world (notably the Engine and its TUN device) are being created, which can take a few to dozens of seconds on Windows. With this change, the ipnserver.New function changes to not take an Engine and to return immediately, not returning an error, and let its Run run immediately. If its ServeHTTP is called when it doesn't yet have a LocalBackend, it returns an error. A TODO in there shows where a future handler will serve status before an engine is available. Future changes will: * delete a bunch of tailscaled_windows.go code and use this new API * add the ipnserver.Server ServerHTTP handler to await the engine being available * use that handler in the Windows GUI client Updates #6522 Change-Id: Iae94e68c235e850b112a72ea24ad0e0959b568ee Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
107 lines
3.1 KiB
Go
107 lines
3.1 KiB
Go
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build go1.19
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"tailscale.com/ipn/ipnlocal"
|
|
"tailscale.com/types/logger"
|
|
"tailscale.com/version/distro"
|
|
)
|
|
|
|
func configureTaildrop(logf logger.Logf, lb *ipnlocal.LocalBackend) {
|
|
dg := distro.Get()
|
|
switch dg {
|
|
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)
|
|
if err != nil {
|
|
logf("%s Taildrop support: %v", dg, err)
|
|
} else {
|
|
logf("%s Taildrop: using %v", dg, path)
|
|
lb.SetDirectFileRoot(path)
|
|
lb.SetDirectFileDoFinalRename(true)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func findTaildropDir(dg distro.Distro) (string, error) {
|
|
const name = "Taildrop"
|
|
switch dg {
|
|
case distro.Synology:
|
|
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)
|
|
}
|
|
|
|
// findSynologyTaildropDir looks for the first volume containing a
|
|
// "Taildrop" directory. We'd run "synoshare --get Taildrop" command
|
|
// but on DSM7 at least, we lack permissions to run that.
|
|
func findSynologyTaildropDir(name string) (dir string, err error) {
|
|
for i := 1; i <= 16; i++ {
|
|
dir = fmt.Sprintf("/volume%v/%s", i, name)
|
|
if fi, err := os.Stat(dir); err == nil && fi.IsDir() {
|
|
return dir, nil
|
|
}
|
|
}
|
|
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 := os.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)
|
|
}
|
|
|
|
// 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)
|
|
}
|