mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
tailscale: update tailfs functions and vars to use drive naming (#11597)
This change updates all tailfs functions and the majority of the tailfs variables to use the new drive naming. Updates tailscale/corp#16827 Signed-off-by: Charlotte Brandhorst-Satzkorn <charlotte@tailscale.com>
This commit is contained in:
parent
2409661a0d
commit
93618a3518
@ -1418,25 +1418,25 @@ func (lc *LocalClient) CheckUpdate(ctx context.Context) (*tailcfg.ClientVersion,
|
|||||||
return &cv, nil
|
return &cv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSSetFileServerAddr instructs TailFS to use the server at addr to access
|
// DriveSetServerAddr instructs Taildrive to use the server at addr to access
|
||||||
// the filesystem. This is used on platforms like Windows and MacOS to let
|
// the filesystem. This is used on platforms like Windows and MacOS to let
|
||||||
// TailFS know to use the file server running in the GUI app.
|
// Taildrive know to use the file server running in the GUI app.
|
||||||
func (lc *LocalClient) TailFSSetFileServerAddr(ctx context.Context, addr string) error {
|
func (lc *LocalClient) DriveSetServerAddr(ctx context.Context, addr string) error {
|
||||||
_, err := lc.send(ctx, "PUT", "/localapi/v0/tailfs/fileserver-address", http.StatusCreated, strings.NewReader(addr))
|
_, err := lc.send(ctx, "PUT", "/localapi/v0/tailfs/fileserver-address", http.StatusCreated, strings.NewReader(addr))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSShareSet adds or updates the given share in the list of shares that
|
// DriveShareSet adds or updates the given share in the list of shares that
|
||||||
// TailFS will serve to remote nodes. If a share with the same name already
|
// Taildrive will serve to remote nodes. If a share with the same name already
|
||||||
// exists, the existing share is replaced/updated.
|
// exists, the existing share is replaced/updated.
|
||||||
func (lc *LocalClient) TailFSShareSet(ctx context.Context, share *drive.Share) error {
|
func (lc *LocalClient) DriveShareSet(ctx context.Context, share *drive.Share) error {
|
||||||
_, err := lc.send(ctx, "PUT", "/localapi/v0/tailfs/shares", http.StatusCreated, jsonBody(share))
|
_, err := lc.send(ctx, "PUT", "/localapi/v0/tailfs/shares", http.StatusCreated, jsonBody(share))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSShareRemove removes the share with the given name from the list of
|
// DriveShareRemove removes the share with the given name from the list of
|
||||||
// shares that TailFS will serve to remote nodes.
|
// shares that Taildrive will serve to remote nodes.
|
||||||
func (lc *LocalClient) TailFSShareRemove(ctx context.Context, name string) error {
|
func (lc *LocalClient) DriveShareRemove(ctx context.Context, name string) error {
|
||||||
_, err := lc.send(
|
_, err := lc.send(
|
||||||
ctx,
|
ctx,
|
||||||
"DELETE",
|
"DELETE",
|
||||||
@ -1446,8 +1446,8 @@ func (lc *LocalClient) TailFSShareRemove(ctx context.Context, name string) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSShareRename renames the share from old to new name.
|
// DriveShareRename renames the share from old to new name.
|
||||||
func (lc *LocalClient) TailFSShareRename(ctx context.Context, oldName, newName string) error {
|
func (lc *LocalClient) DriveShareRename(ctx context.Context, oldName, newName string) error {
|
||||||
_, err := lc.send(
|
_, err := lc.send(
|
||||||
ctx,
|
ctx,
|
||||||
"POST",
|
"POST",
|
||||||
@ -1457,9 +1457,9 @@ func (lc *LocalClient) TailFSShareRename(ctx context.Context, oldName, newName s
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSShareList returns the list of shares that TailFS is currently serving
|
// DriveShareList returns the list of shares that drive is currently serving
|
||||||
// to remote nodes.
|
// to remote nodes.
|
||||||
func (lc *LocalClient) TailFSShareList(ctx context.Context) ([]*drive.Share, error) {
|
func (lc *LocalClient) DriveShareList(ctx context.Context) ([]*drive.Share, error) {
|
||||||
result, err := lc.get200(ctx, "/localapi/v0/tailfs/shares")
|
result, err := lc.get200(ctx, "/localapi/v0/tailfs/shares")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -829,7 +829,7 @@ func TestPrefFlagMapping(t *testing.T) {
|
|||||||
// Handled by TS_DEBUG_FIREWALL_MODE env var, we don't want to have
|
// Handled by TS_DEBUG_FIREWALL_MODE env var, we don't want to have
|
||||||
// a CLI flag for this. The Pref is used by c2n.
|
// a CLI flag for this. The Pref is used by c2n.
|
||||||
continue
|
continue
|
||||||
case "TailFSShares":
|
case "DriveShares":
|
||||||
// Handled by the tailscale share subcommand, we don't want a CLI
|
// Handled by the tailscale share subcommand, we don't want a CLI
|
||||||
// flag for this.
|
// flag for this.
|
||||||
continue
|
continue
|
||||||
|
@ -69,7 +69,7 @@ func runShareSet(ctx context.Context, args []string) error {
|
|||||||
|
|
||||||
name, path := args[0], args[1]
|
name, path := args[0], args[1]
|
||||||
|
|
||||||
err := localClient.TailFSShareSet(ctx, &drive.Share{
|
err := localClient.DriveShareSet(ctx, &drive.Share{
|
||||||
Name: name,
|
Name: name,
|
||||||
Path: path,
|
Path: path,
|
||||||
})
|
})
|
||||||
@ -86,7 +86,7 @@ func runShareRemove(ctx context.Context, args []string) error {
|
|||||||
}
|
}
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
err := localClient.TailFSShareRemove(ctx, name)
|
err := localClient.DriveShareRemove(ctx, name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("Removed share %q\n", name)
|
fmt.Printf("Removed share %q\n", name)
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ func runShareRename(ctx context.Context, args []string) error {
|
|||||||
oldName := args[0]
|
oldName := args[0]
|
||||||
newName := args[1]
|
newName := args[1]
|
||||||
|
|
||||||
err := localClient.TailFSShareRename(ctx, oldName, newName)
|
err := localClient.DriveShareRename(ctx, oldName, newName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("Renamed share %q to %q\n", oldName, newName)
|
fmt.Printf("Renamed share %q to %q\n", oldName, newName)
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ func runShareList(ctx context.Context, args []string) error {
|
|||||||
return fmt.Errorf("usage: tailscale %v", shareListUsage)
|
return fmt.Errorf("usage: tailscale %v", shareListUsage)
|
||||||
}
|
}
|
||||||
|
|
||||||
shares, err := localClient.TailFSShareList(ctx)
|
shares, err := localClient.DriveShareList(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ func defaultPort() uint16 {
|
|||||||
"uninstall-system-daemon": &uninstallSystemDaemon,
|
"uninstall-system-daemon": &uninstallSystemDaemon,
|
||||||
"debug": &debugModeFunc,
|
"debug": &debugModeFunc,
|
||||||
"be-child": &beChildFunc,
|
"be-child": &beChildFunc,
|
||||||
"serve-tailfs": &serveTailFSFunc,
|
"serve-tailfs": &serveDriveFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
var beCLI func() // non-nil if CLI is linked in
|
var beCLI func() // non-nil if CLI is linked in
|
||||||
@ -650,7 +650,7 @@ func tryEngine(logf logger.Logf, sys *tsd.System, name string) (onlyNetstack boo
|
|||||||
Dialer: sys.Dialer.Get(),
|
Dialer: sys.Dialer.Get(),
|
||||||
SetSubsystem: sys.Set,
|
SetSubsystem: sys.Set,
|
||||||
ControlKnobs: sys.ControlKnobs(),
|
ControlKnobs: sys.ControlKnobs(),
|
||||||
TailFSForLocal: driveimpl.NewFileSystemForLocal(logf),
|
DriveForLocal: driveimpl.NewFileSystemForLocal(logf),
|
||||||
}
|
}
|
||||||
|
|
||||||
onlyNetstack = name == "userspace-networking"
|
onlyNetstack = name == "userspace-networking"
|
||||||
@ -753,7 +753,7 @@ func runDebugServer(mux *http.ServeMux, addr string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newNetstack(logf logger.Logf, sys *tsd.System) (*netstack.Impl, error) {
|
func newNetstack(logf logger.Logf, sys *tsd.System) (*netstack.Impl, error) {
|
||||||
tfs, _ := sys.TailFSForLocal.GetOK()
|
tfs, _ := sys.DriveForLocal.GetOK()
|
||||||
ret, err := netstack.Create(logf,
|
ret, err := netstack.Create(logf,
|
||||||
sys.Tun.Get(),
|
sys.Tun.Get(),
|
||||||
sys.Engine.Get(),
|
sys.Engine.Get(),
|
||||||
@ -831,16 +831,16 @@ func beChild(args []string) error {
|
|||||||
return f(args[1:])
|
return f(args[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
var serveTailFSFunc = serveTailFS
|
var serveDriveFunc = serveDrive
|
||||||
|
|
||||||
// serveTailFS serves one or more tailfs on localhost using the WebDAV
|
// serveDrive serves one or more tailfs on localhost using the WebDAV
|
||||||
// protocol. On UNIX and MacOS tailscaled environment, tailfs spawns child
|
// protocol. On UNIX and MacOS tailscaled environment, tailfs spawns child
|
||||||
// tailscaled processes in serve-tailfs mode in order to access the fliesystem
|
// tailscaled processes in serve-tailfs mode in order to access the fliesystem
|
||||||
// as specific (usually unprivileged) users.
|
// as specific (usually unprivileged) users.
|
||||||
//
|
//
|
||||||
// serveTailFS prints the address on which it's listening to stdout so that the
|
// serveDrive prints the address on which it's listening to stdout so that the
|
||||||
// parent process knows where to connect to.
|
// parent process knows where to connect to.
|
||||||
func serveTailFS(args []string) error {
|
func serveDrive(args []string) error {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return errors.New("missing shares")
|
return errors.New("missing shares")
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ func init() {
|
|||||||
drive.DisallowShareAs = true
|
drive.DisallowShareAs = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// The tests in this file simulate real-life TailFS scenarios, but without
|
// The tests in this file simulate real-life Taildrive scenarios, but without
|
||||||
// going over the Tailscale network stack.
|
// going over the Tailscale network stack.
|
||||||
func TestDirectoryListing(t *testing.T) {
|
func TestDirectoryListing(t *testing.T) {
|
||||||
s := newSystem(t)
|
s := newSystem(t)
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
// FileServer is a standalone WebDAV server that dynamically serves up shares.
|
// FileServer is a standalone WebDAV server that dynamically serves up shares.
|
||||||
// It's typically used in a separate process from the actual TailFS server to
|
// It's typically used in a separate process from the actual Taildrive server to
|
||||||
// serve up files as an unprivileged user.
|
// serve up files as an unprivileged user.
|
||||||
type FileServer struct {
|
type FileServer struct {
|
||||||
l net.Listener
|
l net.Listener
|
||||||
|
@ -42,8 +42,8 @@ func NewFileSystemForLocal(logf logger.Logf) *FileSystemForLocal {
|
|||||||
return fs
|
return fs
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileSystemForLocal is the TailFS filesystem exposed to local clients. It
|
// FileSystemForLocal is the Taildrive filesystem exposed to local clients. It
|
||||||
// provides a unified WebDAV interface to remote TailFS shares on other nodes.
|
// provides a unified WebDAV interface to remote Taildrive shares on other nodes.
|
||||||
type FileSystemForLocal struct {
|
type FileSystemForLocal struct {
|
||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
h *compositedav.Handler
|
h *compositedav.Handler
|
||||||
|
@ -44,7 +44,7 @@ func NewFileSystemForRemote(logf logger.Logf) *FileSystemForRemote {
|
|||||||
return fs
|
return fs
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileSystemForRemote implements tailfs.FileSystemForRemote.
|
// FileSystemForRemote implements drive.FileSystemForRemote.
|
||||||
type FileSystemForRemote struct {
|
type FileSystemForRemote struct {
|
||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
lockSystem webdav.LockSystem
|
lockSystem webdav.LockSystem
|
||||||
@ -58,15 +58,15 @@ type FileSystemForRemote struct {
|
|||||||
userServers map[string]*userServer
|
userServers map[string]*userServer
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFileServerAddr implements tailfs.FileSystemForRemote.
|
// SetFileServerAddr implements drive.FileSystemForRemote.
|
||||||
func (s *FileSystemForRemote) SetFileServerAddr(addr string) {
|
func (s *FileSystemForRemote) SetFileServerAddr(addr string) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
s.fileServerAddr = addr
|
s.fileServerAddr = addr
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetShares implements tailfs.FileSystemForRemote. Shares must be sorted
|
// SetShares implements drive.FileSystemForRemote. Shares must be sorted
|
||||||
// according to tailfs.CompareShares.
|
// according to drive.CompareShares.
|
||||||
func (s *FileSystemForRemote) SetShares(shares []*drive.Share) {
|
func (s *FileSystemForRemote) SetShares(shares []*drive.Share) {
|
||||||
userServers := make(map[string]*userServer)
|
userServers := make(map[string]*userServer)
|
||||||
if drive.AllowShareAs() {
|
if drive.AllowShareAs() {
|
||||||
@ -176,7 +176,7 @@ func (s *FileSystemForRemote) buildChild(share *drive.Share) *compositedav.Child
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeHTTPWithPerms implements tailfs.FileSystemForRemote.
|
// ServeHTTPWithPerms implements drive.FileSystemForRemote.
|
||||||
func (s *FileSystemForRemote) ServeHTTPWithPerms(permissions drive.Permissions, w http.ResponseWriter, r *http.Request) {
|
func (s *FileSystemForRemote) ServeHTTPWithPerms(permissions drive.Permissions, w http.ResponseWriter, r *http.Request) {
|
||||||
isWrite := writeMethods[r.Method]
|
isWrite := writeMethods[r.Method]
|
||||||
if isWrite {
|
if isWrite {
|
||||||
@ -228,7 +228,7 @@ func (s *FileSystemForRemote) closeChildren(children map[string]*compositedav.Ch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close() implements tailfs.FileSystemForRemote.
|
// Close() implements drive.FileSystemForRemote.
|
||||||
func (s *FileSystemForRemote) Close() error {
|
func (s *FileSystemForRemote) Close() error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
userServers := s.userServers
|
userServers := s.userServers
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) Tailscale Inc & AUTHORS
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
// Package shared contains types and functions shared by different tailfs
|
// Package shared contains types and functions shared by different drive
|
||||||
// packages.
|
// packages.
|
||||||
package shared
|
package shared
|
||||||
|
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
// SPDX-License-Identifier: BSD-3-Clause
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
// Package drive provides a filesystem that allows sharing folders between
|
// Package drive provides a filesystem that allows sharing folders between
|
||||||
// Tailscale nodes using WebDAV. The actual implementation of the core drive
|
// Tailscale nodes using WebDAV. The actual implementation of the core Taildrive
|
||||||
// functionality lives in package driveimpl. These packages are separated to
|
// functionality lives in package driveimpl. These packages are separated to
|
||||||
// allow users of drive to refer to the interfaces without having a hard
|
// allow users of Taildrive to refer to the interfaces without having a hard
|
||||||
// dependency on drive, so that programs which don't actually use drive can
|
// dependency on Taildrive, so that programs which don't actually use Taildrive can
|
||||||
// avoid its transitive dependencies.
|
// avoid its transitive dependencies.
|
||||||
package drive
|
package drive
|
||||||
|
|
||||||
@ -14,15 +14,15 @@
|
|||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Remote represents a remote TailFS node.
|
// Remote represents a remote Taildrive node.
|
||||||
type Remote struct {
|
type Remote struct {
|
||||||
Name string
|
Name string
|
||||||
URL string
|
URL string
|
||||||
Available func() bool
|
Available func() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileSystemForLocal is the TailFS filesystem exposed to local clients. It
|
// FileSystemForLocal is the Taildrive filesystem exposed to local clients. It
|
||||||
// provides a unified WebDAV interface to remote TailFS shares on other nodes.
|
// provides a unified WebDAV interface to remote Taildrive shares on other nodes.
|
||||||
type FileSystemForLocal interface {
|
type FileSystemForLocal interface {
|
||||||
// HandleConn handles connections from local WebDAV clients
|
// HandleConn handles connections from local WebDAV clients
|
||||||
HandleConn(conn net.Conn, remoteAddr net.Addr) error
|
HandleConn(conn net.Conn, remoteAddr net.Addr) error
|
||||||
|
@ -22,7 +22,7 @@ func AllowShareAs() bool {
|
|||||||
return !DisallowShareAs && doAllowShareAs()
|
return !DisallowShareAs && doAllowShareAs()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Share configures a folder to be shared through TailFS.
|
// Share configures a folder to be shared through drive.
|
||||||
type Share struct {
|
type Share struct {
|
||||||
// Name is how this share appears on remote nodes.
|
// Name is how this share appears on remote nodes.
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
@ -78,7 +78,7 @@ func CompareShares(a, b *Share) int {
|
|||||||
return strings.Compare(a.Name, b.Name)
|
return strings.Compare(a.Name, b.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileSystemForRemote is the TailFS filesystem exposed to remote nodes. It
|
// FileSystemForRemote is the drive filesystem exposed to remote nodes. It
|
||||||
// provides a unified WebDAV interface to local directories that have been
|
// provides a unified WebDAV interface to local directories that have been
|
||||||
// shared.
|
// shared.
|
||||||
type FileSystemForRemote interface {
|
type FileSystemForRemote interface {
|
||||||
|
@ -68,7 +68,7 @@ type EngineStatus struct {
|
|||||||
NotifyInitialNetMap // if set, the first Notify message (sent immediately) will contain the current NetMap
|
NotifyInitialNetMap // if set, the first Notify message (sent immediately) will contain the current NetMap
|
||||||
|
|
||||||
NotifyNoPrivateKeys // if set, private keys that would normally be sent in updates are zeroed out
|
NotifyNoPrivateKeys // if set, private keys that would normally be sent in updates are zeroed out
|
||||||
NotifyInitialTailFSShares // if set, the first Notify message (sent immediately) will contain the current TailFS Shares
|
NotifyInitialDriveShares // if set, the first Notify message (sent immediately) will contain the current Taildrive Shares
|
||||||
NotifyInitialOutgoingFiles // if set, the first Notify message (sent immediately) will contain the current Taildrop OutgoingFiles
|
NotifyInitialOutgoingFiles // if set, the first Notify message (sent immediately) will contain the current Taildrop OutgoingFiles
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -130,13 +130,13 @@ type Notify struct {
|
|||||||
// is available.
|
// is available.
|
||||||
ClientVersion *tailcfg.ClientVersion `json:",omitempty"`
|
ClientVersion *tailcfg.ClientVersion `json:",omitempty"`
|
||||||
|
|
||||||
// TailFSShares tracks the full set of current TailFSShares that we're
|
// DriveShares tracks the full set of current DriveShares that we're
|
||||||
// publishing. Some client applications, like the MacOS and Windows clients,
|
// publishing. Some client applications, like the MacOS and Windows clients,
|
||||||
// will listen for updates to this and handle serving these shares under
|
// will listen for updates to this and handle serving these shares under
|
||||||
// the identity of the unprivileged user that is running the application. A
|
// the identity of the unprivileged user that is running the application. A
|
||||||
// nil value here means that we're not broadcasting shares information, an
|
// nil value here means that we're not broadcasting shares information, an
|
||||||
// empty value means that there are no shares.
|
// empty value means that there are no shares.
|
||||||
TailFSShares views.SliceView[*drive.Share, drive.ShareView]
|
DriveShares views.SliceView[*drive.Share, drive.ShareView]
|
||||||
|
|
||||||
// type is mirrored in xcode/Shared/IPN.swift
|
// type is mirrored in xcode/Shared/IPN.swift
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,10 @@ func (src *Prefs) Clone() *Prefs {
|
|||||||
*dst = *src
|
*dst = *src
|
||||||
dst.AdvertiseTags = append(src.AdvertiseTags[:0:0], src.AdvertiseTags...)
|
dst.AdvertiseTags = append(src.AdvertiseTags[:0:0], src.AdvertiseTags...)
|
||||||
dst.AdvertiseRoutes = append(src.AdvertiseRoutes[:0:0], src.AdvertiseRoutes...)
|
dst.AdvertiseRoutes = append(src.AdvertiseRoutes[:0:0], src.AdvertiseRoutes...)
|
||||||
if src.TailFSShares != nil {
|
if src.DriveShares != nil {
|
||||||
dst.TailFSShares = make([]*drive.Share, len(src.TailFSShares))
|
dst.DriveShares = make([]*drive.Share, len(src.DriveShares))
|
||||||
for i := range dst.TailFSShares {
|
for i := range dst.DriveShares {
|
||||||
dst.TailFSShares[i] = src.TailFSShares[i].Clone()
|
dst.DriveShares[i] = src.DriveShares[i].Clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dst.Persist = src.Persist.Clone()
|
dst.Persist = src.Persist.Clone()
|
||||||
@ -63,7 +63,7 @@ func (src *Prefs) Clone() *Prefs {
|
|||||||
AppConnector AppConnectorPrefs
|
AppConnector AppConnectorPrefs
|
||||||
PostureChecking bool
|
PostureChecking bool
|
||||||
NetfilterKind string
|
NetfilterKind string
|
||||||
TailFSShares []*drive.Share
|
DriveShares []*drive.Share
|
||||||
Persist *persist.Persist
|
Persist *persist.Persist
|
||||||
}{})
|
}{})
|
||||||
|
|
||||||
|
@ -92,8 +92,8 @@ func (v PrefsView) AutoUpdate() AutoUpdatePrefs { return v.ж.AutoUpda
|
|||||||
func (v PrefsView) AppConnector() AppConnectorPrefs { return v.ж.AppConnector }
|
func (v PrefsView) AppConnector() AppConnectorPrefs { return v.ж.AppConnector }
|
||||||
func (v PrefsView) PostureChecking() bool { return v.ж.PostureChecking }
|
func (v PrefsView) PostureChecking() bool { return v.ж.PostureChecking }
|
||||||
func (v PrefsView) NetfilterKind() string { return v.ж.NetfilterKind }
|
func (v PrefsView) NetfilterKind() string { return v.ж.NetfilterKind }
|
||||||
func (v PrefsView) TailFSShares() views.SliceView[*drive.Share, drive.ShareView] {
|
func (v PrefsView) DriveShares() views.SliceView[*drive.Share, drive.ShareView] {
|
||||||
return views.SliceOfViews[*drive.Share, drive.ShareView](v.ж.TailFSShares)
|
return views.SliceOfViews[*drive.Share, drive.ShareView](v.ж.DriveShares)
|
||||||
}
|
}
|
||||||
func (v PrefsView) Persist() persist.PersistView { return v.ж.Persist.View() }
|
func (v PrefsView) Persist() persist.PersistView { return v.ж.Persist.View() }
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ func (v PrefsView) Persist() persist.PersistView { return v.ж.Persist.View() }
|
|||||||
AppConnector AppConnectorPrefs
|
AppConnector AppConnectorPrefs
|
||||||
PostureChecking bool
|
PostureChecking bool
|
||||||
NetfilterKind string
|
NetfilterKind string
|
||||||
TailFSShares []*drive.Share
|
DriveShares []*drive.Share
|
||||||
Persist *persist.Persist
|
Persist *persist.Persist
|
||||||
}{})
|
}{})
|
||||||
|
|
||||||
|
@ -19,61 +19,61 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TailFSLocalPort is the port on which the TailFS listens for location
|
// DriveLocalPort is the port on which the Taildrive listens for location
|
||||||
// connections on quad 100.
|
// connections on quad 100.
|
||||||
TailFSLocalPort = 8080
|
DriveLocalPort = 8080
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
shareNameRegex = regexp.MustCompile(`^[a-z0-9_\(\) ]+$`)
|
shareNameRegex = regexp.MustCompile(`^[a-z0-9_\(\) ]+$`)
|
||||||
ErrTailFSNotEnabled = errors.New("TailFS not enabled")
|
ErrDriveNotEnabled = errors.New("TailFS not enabled")
|
||||||
ErrInvalidShareName = errors.New("Share names may only contain the letters a-z, underscore _, parentheses (), or spaces")
|
ErrInvalidShareName = errors.New("Share names may only contain the letters a-z, underscore _, parentheses (), or spaces")
|
||||||
)
|
)
|
||||||
|
|
||||||
// TailFSSharingEnabled reports whether sharing to remote nodes via tailfs is
|
// DriveSharingEnabled reports whether sharing to remote nodes via Taildrive is
|
||||||
// enabled. This is currently based on checking for the tailfs:share node
|
// enabled. This is currently based on checking for the tailfs:share node
|
||||||
// attribute.
|
// attribute.
|
||||||
func (b *LocalBackend) TailFSSharingEnabled() bool {
|
func (b *LocalBackend) DriveSharingEnabled() bool {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
return b.tailFSSharingEnabledLocked()
|
return b.driveSharingEnabledLocked()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) tailFSSharingEnabledLocked() bool {
|
func (b *LocalBackend) driveSharingEnabledLocked() bool {
|
||||||
return b.netMap != nil && b.netMap.SelfNode.HasCap(tailcfg.NodeAttrsTailFSShare)
|
return b.netMap != nil && b.netMap.SelfNode.HasCap(tailcfg.NodeAttrsTailFSShare)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSAccessEnabled reports whether accessing TailFS shares on remote nodes
|
// DriveAccessEnabled reports whether accessing Taildrive shares on remote nodes
|
||||||
// is enabled. This is currently based on checking for the tailfs:access node
|
// is enabled. This is currently based on checking for the tailfs:access node
|
||||||
// attribute.
|
// attribute.
|
||||||
func (b *LocalBackend) TailFSAccessEnabled() bool {
|
func (b *LocalBackend) DriveAccessEnabled() bool {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
return b.tailFSAccessEnabledLocked()
|
return b.driveAccessEnabledLocked()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) tailFSAccessEnabledLocked() bool {
|
func (b *LocalBackend) driveAccessEnabledLocked() bool {
|
||||||
return b.netMap != nil && b.netMap.SelfNode.HasCap(tailcfg.NodeAttrsTailFSAccess)
|
return b.netMap != nil && b.netMap.SelfNode.HasCap(tailcfg.NodeAttrsTailFSAccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSSetFileServerAddr tells tailfs to use the given address for connecting
|
// DriveSetServerAddr tells Taildrive to use the given address for connecting
|
||||||
// to the tailfs.FileServer that's exposing local files as an unprivileged
|
// to the drive.FileServer that's exposing local files as an unprivileged
|
||||||
// user.
|
// user.
|
||||||
func (b *LocalBackend) TailFSSetFileServerAddr(addr string) error {
|
func (b *LocalBackend) DriveSetServerAddr(addr string) error {
|
||||||
fs, ok := b.sys.TailFSForRemote.GetOK()
|
fs, ok := b.sys.DriveForRemote.GetOK()
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrTailFSNotEnabled
|
return ErrDriveNotEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.SetFileServerAddr(addr)
|
fs.SetFileServerAddr(addr)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSSetShare adds the given share if no share with that name exists, or
|
// DriveSetShare adds the given share if no share with that name exists, or
|
||||||
// replaces the existing share if one with the same name already exists. To
|
// replaces the existing share if one with the same name already exists. To
|
||||||
// avoid potential incompatibilities across file systems, share names are
|
// avoid potential incompatibilities across file systems, share names are
|
||||||
// limited to alphanumeric characters and the underscore _.
|
// limited to alphanumeric characters and the underscore _.
|
||||||
func (b *LocalBackend) TailFSSetShare(share *drive.Share) error {
|
func (b *LocalBackend) DriveSetShare(share *drive.Share) error {
|
||||||
var err error
|
var err error
|
||||||
share.Name, err = normalizeShareName(share.Name)
|
share.Name, err = normalizeShareName(share.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -81,13 +81,13 @@ func (b *LocalBackend) TailFSSetShare(share *drive.Share) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
shares, err := b.tailFSSetShareLocked(share)
|
shares, err := b.driveSetShareLocked(share)
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.tailFSNotifyShares(shares)
|
b.driveNotifyShares(shares)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,12 +108,12 @@ func normalizeShareName(name string) (string, error) {
|
|||||||
return name, nil
|
return name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) tailFSSetShareLocked(share *drive.Share) (views.SliceView[*drive.Share, drive.ShareView], error) {
|
func (b *LocalBackend) driveSetShareLocked(share *drive.Share) (views.SliceView[*drive.Share, drive.ShareView], error) {
|
||||||
existingShares := b.pm.prefs.TailFSShares()
|
existingShares := b.pm.prefs.DriveShares()
|
||||||
|
|
||||||
fs, ok := b.sys.TailFSForRemote.GetOK()
|
fs, ok := b.sys.DriveForRemote.GetOK()
|
||||||
if !ok {
|
if !ok {
|
||||||
return existingShares, ErrTailFSNotEnabled
|
return existingShares, ErrDriveNotEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
addedShare := false
|
addedShare := false
|
||||||
@ -133,23 +133,23 @@ func (b *LocalBackend) tailFSSetShareLocked(share *drive.Share) (views.SliceView
|
|||||||
shares = append(shares, share)
|
shares = append(shares, share)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := b.tailFSSetSharesLocked(shares)
|
err := b.driveSetSharesLocked(shares)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return existingShares, err
|
return existingShares, err
|
||||||
}
|
}
|
||||||
fs.SetShares(shares)
|
fs.SetShares(shares)
|
||||||
|
|
||||||
return b.pm.prefs.TailFSShares(), nil
|
return b.pm.prefs.DriveShares(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSRenameShare renames the share at old name to new name. To avoid
|
// DriveRenameShare renames the share at old name to new name. To avoid
|
||||||
// potential incompatibilities across file systems, the new share name is
|
// potential incompatibilities across file systems, the new share name is
|
||||||
// limited to alphanumeric characters and the underscore _.
|
// limited to alphanumeric characters and the underscore _.
|
||||||
// Any of the following will result in an error.
|
// Any of the following will result in an error.
|
||||||
// - no share found under old name
|
// - no share found under old name
|
||||||
// - new share name contains disallowed characters
|
// - new share name contains disallowed characters
|
||||||
// - share already exists under new name
|
// - share already exists under new name
|
||||||
func (b *LocalBackend) TailFSRenameShare(oldName, newName string) error {
|
func (b *LocalBackend) DriveRenameShare(oldName, newName string) error {
|
||||||
var err error
|
var err error
|
||||||
newName, err = normalizeShareName(newName)
|
newName, err = normalizeShareName(newName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -157,22 +157,22 @@ func (b *LocalBackend) TailFSRenameShare(oldName, newName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
shares, err := b.tailFSRenameShareLocked(oldName, newName)
|
shares, err := b.driveRenameShareLocked(oldName, newName)
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.tailFSNotifyShares(shares)
|
b.driveNotifyShares(shares)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) tailFSRenameShareLocked(oldName, newName string) (views.SliceView[*drive.Share, drive.ShareView], error) {
|
func (b *LocalBackend) driveRenameShareLocked(oldName, newName string) (views.SliceView[*drive.Share, drive.ShareView], error) {
|
||||||
existingShares := b.pm.prefs.TailFSShares()
|
existingShares := b.pm.prefs.DriveShares()
|
||||||
|
|
||||||
fs, ok := b.sys.TailFSForRemote.GetOK()
|
fs, ok := b.sys.DriveForRemote.GetOK()
|
||||||
if !ok {
|
if !ok {
|
||||||
return existingShares, ErrTailFSNotEnabled
|
return existingShares, ErrDriveNotEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
@ -197,18 +197,18 @@ func (b *LocalBackend) tailFSRenameShareLocked(oldName, newName string) (views.S
|
|||||||
}
|
}
|
||||||
|
|
||||||
slices.SortFunc(shares, drive.CompareShares)
|
slices.SortFunc(shares, drive.CompareShares)
|
||||||
err := b.tailFSSetSharesLocked(shares)
|
err := b.driveSetSharesLocked(shares)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return existingShares, err
|
return existingShares, err
|
||||||
}
|
}
|
||||||
fs.SetShares(shares)
|
fs.SetShares(shares)
|
||||||
|
|
||||||
return b.pm.prefs.TailFSShares(), nil
|
return b.pm.prefs.DriveShares(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSRemoveShare removes the named share. Share names are forced to
|
// DriveRemoveShare removes the named share. Share names are forced to
|
||||||
// lowercase.
|
// lowercase.
|
||||||
func (b *LocalBackend) TailFSRemoveShare(name string) error {
|
func (b *LocalBackend) DriveRemoveShare(name string) error {
|
||||||
// Force all share names to lowercase to avoid potential incompatibilities
|
// Force all share names to lowercase to avoid potential incompatibilities
|
||||||
// with clients that don't support case-sensitive filenames.
|
// with clients that don't support case-sensitive filenames.
|
||||||
var err error
|
var err error
|
||||||
@ -218,22 +218,22 @@ func (b *LocalBackend) TailFSRemoveShare(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
shares, err := b.tailFSRemoveShareLocked(name)
|
shares, err := b.driveRemoveShareLocked(name)
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.tailFSNotifyShares(shares)
|
b.driveNotifyShares(shares)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) tailFSRemoveShareLocked(name string) (views.SliceView[*drive.Share, drive.ShareView], error) {
|
func (b *LocalBackend) driveRemoveShareLocked(name string) (views.SliceView[*drive.Share, drive.ShareView], error) {
|
||||||
existingShares := b.pm.prefs.TailFSShares()
|
existingShares := b.pm.prefs.DriveShares()
|
||||||
|
|
||||||
fs, ok := b.sys.TailFSForRemote.GetOK()
|
fs, ok := b.sys.DriveForRemote.GetOK()
|
||||||
if !ok {
|
if !ok {
|
||||||
return existingShares, ErrTailFSNotEnabled
|
return existingShares, ErrDriveNotEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
@ -251,53 +251,53 @@ func (b *LocalBackend) tailFSRemoveShareLocked(name string) (views.SliceView[*dr
|
|||||||
return existingShares, os.ErrNotExist
|
return existingShares, os.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
err := b.tailFSSetSharesLocked(shares)
|
err := b.driveSetSharesLocked(shares)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return existingShares, err
|
return existingShares, err
|
||||||
}
|
}
|
||||||
fs.SetShares(shares)
|
fs.SetShares(shares)
|
||||||
|
|
||||||
return b.pm.prefs.TailFSShares(), nil
|
return b.pm.prefs.DriveShares(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) tailFSSetSharesLocked(shares []*drive.Share) error {
|
func (b *LocalBackend) driveSetSharesLocked(shares []*drive.Share) error {
|
||||||
prefs := b.pm.prefs.AsStruct()
|
prefs := b.pm.prefs.AsStruct()
|
||||||
prefs.ApplyEdits(&ipn.MaskedPrefs{
|
prefs.ApplyEdits(&ipn.MaskedPrefs{
|
||||||
Prefs: ipn.Prefs{
|
Prefs: ipn.Prefs{
|
||||||
TailFSShares: shares,
|
DriveShares: shares,
|
||||||
},
|
},
|
||||||
TailFSSharesSet: true,
|
DriveSharesSet: true,
|
||||||
})
|
})
|
||||||
return b.pm.setPrefsLocked(prefs.View())
|
return b.pm.setPrefsLocked(prefs.View())
|
||||||
}
|
}
|
||||||
|
|
||||||
// tailFSNotifyShares notifies IPN bus listeners (e.g. Mac Application process)
|
// driveNotifyShares notifies IPN bus listeners (e.g. Mac Application process)
|
||||||
// about the latest list of shares.
|
// about the latest list of shares.
|
||||||
func (b *LocalBackend) tailFSNotifyShares(shares views.SliceView[*drive.Share, drive.ShareView]) {
|
func (b *LocalBackend) driveNotifyShares(shares views.SliceView[*drive.Share, drive.ShareView]) {
|
||||||
// Ensures shares is not nil to distinguish "no shares" from "not notifying shares"
|
// Ensures shares is not nil to distinguish "no shares" from "not notifying shares"
|
||||||
if shares.IsNil() {
|
if shares.IsNil() {
|
||||||
shares = views.SliceOfViews(make([]*drive.Share, 0))
|
shares = views.SliceOfViews(make([]*drive.Share, 0))
|
||||||
}
|
}
|
||||||
b.send(ipn.Notify{TailFSShares: shares})
|
b.send(ipn.Notify{DriveShares: shares})
|
||||||
}
|
}
|
||||||
|
|
||||||
// tailFSNotifyCurrentSharesLocked sends an ipn.Notify if the current set of
|
// driveNotifyCurrentSharesLocked sends an ipn.Notify if the current set of
|
||||||
// shares has changed since the last notification.
|
// shares has changed since the last notification.
|
||||||
func (b *LocalBackend) tailFSNotifyCurrentSharesLocked() {
|
func (b *LocalBackend) driveNotifyCurrentSharesLocked() {
|
||||||
var shares views.SliceView[*drive.Share, drive.ShareView]
|
var shares views.SliceView[*drive.Share, drive.ShareView]
|
||||||
if b.tailFSSharingEnabledLocked() {
|
if b.driveSharingEnabledLocked() {
|
||||||
// Only populate shares if sharing is enabled.
|
// Only populate shares if sharing is enabled.
|
||||||
shares = b.pm.prefs.TailFSShares()
|
shares = b.pm.prefs.DriveShares()
|
||||||
}
|
}
|
||||||
|
|
||||||
lastNotified := b.lastNotifiedTailFSShares.Load()
|
lastNotified := b.lastNotifiedDriveShares.Load()
|
||||||
if lastNotified == nil || !tailFSShareViewsEqual(lastNotified, shares) {
|
if lastNotified == nil || !driveShareViewsEqual(lastNotified, shares) {
|
||||||
// Do the below on a goroutine to avoid deadlocking on b.mu in b.send().
|
// Do the below on a goroutine to avoid deadlocking on b.mu in b.send().
|
||||||
go b.tailFSNotifyShares(shares)
|
go b.driveNotifyShares(shares)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tailFSShareViewsEqual(a *views.SliceView[*drive.Share, drive.ShareView], b views.SliceView[*drive.Share, drive.ShareView]) bool {
|
func driveShareViewsEqual(a *views.SliceView[*drive.Share, drive.ShareView], b views.SliceView[*drive.Share, drive.ShareView]) bool {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -315,35 +315,35 @@ func tailFSShareViewsEqual(a *views.SliceView[*drive.Share, drive.ShareView], b
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// TailFSGetShares() gets the current list of TailFS shares, sorted by name.
|
// DriveGetShares gets the current list of Taildrive shares, sorted by name.
|
||||||
func (b *LocalBackend) TailFSGetShares() views.SliceView[*drive.Share, drive.ShareView] {
|
func (b *LocalBackend) DriveGetShares() views.SliceView[*drive.Share, drive.ShareView] {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
return b.pm.prefs.TailFSShares()
|
return b.pm.prefs.DriveShares()
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateTailFSPeersLocked sets all applicable peers from the netmap as tailfs
|
// updateDrivePeersLocked sets all applicable peers from the netmap as Taildrive
|
||||||
// remotes.
|
// remotes.
|
||||||
func (b *LocalBackend) updateTailFSPeersLocked(nm *netmap.NetworkMap) {
|
func (b *LocalBackend) updateDrivePeersLocked(nm *netmap.NetworkMap) {
|
||||||
fs, ok := b.sys.TailFSForLocal.GetOK()
|
fs, ok := b.sys.DriveForLocal.GetOK()
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var tailFSRemotes []*drive.Remote
|
var driveRemotes []*drive.Remote
|
||||||
if b.tailFSAccessEnabledLocked() {
|
if b.driveAccessEnabledLocked() {
|
||||||
// Only populate peers if access is enabled, otherwise leave blank.
|
// Only populate peers if access is enabled, otherwise leave blank.
|
||||||
tailFSRemotes = b.tailFSRemotesFromPeers(nm)
|
driveRemotes = b.driveRemotesFromPeers(nm)
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.SetRemotes(b.netMap.Domain, tailFSRemotes, &tailFSTransport{b: b})
|
fs.SetRemotes(b.netMap.Domain, driveRemotes, &driveTransport{b: b})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) tailFSRemotesFromPeers(nm *netmap.NetworkMap) []*drive.Remote {
|
func (b *LocalBackend) driveRemotesFromPeers(nm *netmap.NetworkMap) []*drive.Remote {
|
||||||
tailFSRemotes := make([]*drive.Remote, 0, len(nm.Peers))
|
driveRemotes := make([]*drive.Remote, 0, len(nm.Peers))
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
// Exclude mullvad exit nodes from list of TailFS peers
|
// Exclude mullvad exit nodes from list of Taildrive peers
|
||||||
// TODO(oxtoacart) - once we have a better mechanism for finding only accessible sharers
|
// TODO(oxtoacart) - once we have a better mechanism for finding only accessible sharers
|
||||||
// (see below) we can remove this logic.
|
// (see below) we can remove this logic.
|
||||||
if strings.HasSuffix(p.Name(), ".mullvad.ts.net.") {
|
if strings.HasSuffix(p.Name(), ".mullvad.ts.net.") {
|
||||||
@ -352,7 +352,7 @@ func (b *LocalBackend) tailFSRemotesFromPeers(nm *netmap.NetworkMap) []*drive.Re
|
|||||||
|
|
||||||
peerID := p.ID()
|
peerID := p.ID()
|
||||||
url := fmt.Sprintf("%s/%s", peerAPIBase(nm, p), tailFSPrefix[1:])
|
url := fmt.Sprintf("%s/%s", peerAPIBase(nm, p), tailFSPrefix[1:])
|
||||||
tailFSRemotes = append(tailFSRemotes, &drive.Remote{
|
driveRemotes = append(driveRemotes, &drive.Remote{
|
||||||
Name: p.DisplayName(false),
|
Name: p.DisplayName(false),
|
||||||
URL: url,
|
URL: url,
|
||||||
Available: func() bool {
|
Available: func() bool {
|
||||||
@ -381,5 +381,5 @@ func (b *LocalBackend) tailFSRemotesFromPeers(nm *netmap.NetworkMap) []*drive.Re
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return tailFSRemotes
|
return driveRemotes
|
||||||
}
|
}
|
||||||
|
@ -316,9 +316,9 @@ type LocalBackend struct {
|
|||||||
// Last ClientVersion received in MapResponse, guarded by mu.
|
// Last ClientVersion received in MapResponse, guarded by mu.
|
||||||
lastClientVersion *tailcfg.ClientVersion
|
lastClientVersion *tailcfg.ClientVersion
|
||||||
|
|
||||||
// lastNotifiedTailFSShares keeps track of the last set of shares that we
|
// lastNotifiedDriveShares keeps track of the last set of shares that we
|
||||||
// notified about.
|
// notified about.
|
||||||
lastNotifiedTailFSShares atomic.Pointer[views.SliceView[*drive.Share, drive.ShareView]]
|
lastNotifiedDriveShares atomic.Pointer[views.SliceView[*drive.Share, drive.ShareView]]
|
||||||
|
|
||||||
// outgoingFiles keeps track of Taildrop outgoing files keyed to their OutgoingFile.ID
|
// outgoingFiles keeps track of Taildrop outgoing files keyed to their OutgoingFile.ID
|
||||||
outgoingFiles map[string]*ipn.OutgoingFile
|
outgoingFiles map[string]*ipn.OutgoingFile
|
||||||
@ -442,10 +442,10 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize TailFS shares from saved state
|
// initialize Taildrive shares from saved state
|
||||||
fs, ok := b.sys.TailFSForRemote.GetOK()
|
fs, ok := b.sys.DriveForRemote.GetOK()
|
||||||
if ok {
|
if ok {
|
||||||
currentShares := b.pm.prefs.TailFSShares()
|
currentShares := b.pm.prefs.DriveShares()
|
||||||
if currentShares.Len() > 0 {
|
if currentShares.Len() > 0 {
|
||||||
var shares []*drive.Share
|
var shares []*drive.Share
|
||||||
for i := 0; i < currentShares.Len(); i++ {
|
for i := 0; i < currentShares.Len(); i++ {
|
||||||
@ -2292,7 +2292,7 @@ func (b *LocalBackend) WatchNotifications(ctx context.Context, mask ipn.NotifyWa
|
|||||||
|
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
|
|
||||||
const initialBits = ipn.NotifyInitialState | ipn.NotifyInitialPrefs | ipn.NotifyInitialNetMap | ipn.NotifyInitialTailFSShares
|
const initialBits = ipn.NotifyInitialState | ipn.NotifyInitialPrefs | ipn.NotifyInitialNetMap | ipn.NotifyInitialDriveShares
|
||||||
if mask&initialBits != 0 {
|
if mask&initialBits != 0 {
|
||||||
ini = &ipn.Notify{Version: version.Long()}
|
ini = &ipn.Notify{Version: version.Long()}
|
||||||
if mask&ipn.NotifyInitialState != 0 {
|
if mask&ipn.NotifyInitialState != 0 {
|
||||||
@ -2308,8 +2308,8 @@ func (b *LocalBackend) WatchNotifications(ctx context.Context, mask ipn.NotifyWa
|
|||||||
if mask&ipn.NotifyInitialNetMap != 0 {
|
if mask&ipn.NotifyInitialNetMap != 0 {
|
||||||
ini.NetMap = b.netMap
|
ini.NetMap = b.netMap
|
||||||
}
|
}
|
||||||
if mask&ipn.NotifyInitialTailFSShares != 0 && b.tailFSSharingEnabledLocked() {
|
if mask&ipn.NotifyInitialDriveShares != 0 && b.driveSharingEnabledLocked() {
|
||||||
ini.TailFSShares = b.pm.prefs.TailFSShares()
|
ini.DriveShares = b.pm.prefs.DriveShares()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3382,8 +3382,8 @@ func (b *LocalBackend) TCPHandlerForDst(src, dst netip.AddrPort) (handler func(c
|
|||||||
return b.handleWebClientConn, opts
|
return b.handleWebClientConn, opts
|
||||||
}
|
}
|
||||||
return b.HandleQuad100Port80Conn, opts
|
return b.HandleQuad100Port80Conn, opts
|
||||||
case TailFSLocalPort:
|
case DriveLocalPort:
|
||||||
return b.handleTailFSConn, opts
|
return b.handleDriveConn, opts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3417,9 +3417,9 @@ func (b *LocalBackend) TCPHandlerForDst(src, dst netip.AddrPort) (handler func(c
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) handleTailFSConn(conn net.Conn) error {
|
func (b *LocalBackend) handleDriveConn(conn net.Conn) error {
|
||||||
fs, ok := b.sys.TailFSForLocal.GetOK()
|
fs, ok := b.sys.DriveForLocal.GetOK()
|
||||||
if !ok || !b.TailFSAccessEnabled() {
|
if !ok || !b.DriveAccessEnabled() {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -4729,8 +4729,8 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.updateTailFSPeersLocked(nm)
|
b.updateDrivePeersLocked(nm)
|
||||||
b.tailFSNotifyCurrentSharesLocked()
|
b.driveNotifyCurrentSharesLocked()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) updatePeersFromNetmapLocked(nm *netmap.NetworkMap) {
|
func (b *LocalBackend) updatePeersFromNetmapLocked(nm *netmap.NetworkMap) {
|
||||||
@ -4757,10 +4757,10 @@ func (b *LocalBackend) updatePeersFromNetmapLocked(nm *netmap.NetworkMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// tailFSTransport is an http.RoundTripper that uses the latest value of
|
// driveTransport is an http.RoundTripper that uses the latest value of
|
||||||
// b.Dialer().PeerAPITransport() for each round trip and imposes a short
|
// b.Dialer().PeerAPITransport() for each round trip and imposes a short
|
||||||
// dial timeout to avoid hanging on connecting to offline/unreachable hosts.
|
// dial timeout to avoid hanging on connecting to offline/unreachable hosts.
|
||||||
type tailFSTransport struct {
|
type driveTransport struct {
|
||||||
b *LocalBackend
|
b *LocalBackend
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4817,7 +4817,7 @@ func (rbw *responseBodyWrapper) Close() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tailFSTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
func (dt *driveTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
||||||
bw := &requestBodyWrapper{}
|
bw := &requestBodyWrapper{}
|
||||||
if req.Body != nil {
|
if req.Body != nil {
|
||||||
bw.ReadCloser = req.Body
|
bw.ReadCloser = req.Body
|
||||||
@ -4839,24 +4839,24 @@ func (t *tailFSTransport) RoundTrip(req *http.Request) (resp *http.Response, err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t.b.mu.Lock()
|
dt.b.mu.Lock()
|
||||||
selfNodeKey := t.b.netMap.SelfNode.Key().ShortString()
|
selfNodeKey := dt.b.netMap.SelfNode.Key().ShortString()
|
||||||
t.b.mu.Unlock()
|
dt.b.mu.Unlock()
|
||||||
n, _, ok := t.b.WhoIs(netip.MustParseAddrPort(req.URL.Host))
|
n, _, ok := dt.b.WhoIs(netip.MustParseAddrPort(req.URL.Host))
|
||||||
shareNodeKey := "unknown"
|
shareNodeKey := "unknown"
|
||||||
if ok {
|
if ok {
|
||||||
shareNodeKey = string(n.Key().ShortString())
|
shareNodeKey = string(n.Key().ShortString())
|
||||||
}
|
}
|
||||||
|
|
||||||
rbw := responseBodyWrapper{
|
rbw := responseBodyWrapper{
|
||||||
log: t.b.logf,
|
log: dt.b.logf,
|
||||||
method: req.Method,
|
method: req.Method,
|
||||||
bytesTx: int64(bw.bytesRead),
|
bytesTx: int64(bw.bytesRead),
|
||||||
selfNodeKey: selfNodeKey,
|
selfNodeKey: selfNodeKey,
|
||||||
shareNodeKey: shareNodeKey,
|
shareNodeKey: shareNodeKey,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
contentLength: resp.ContentLength,
|
contentLength: resp.ContentLength,
|
||||||
fileExtension: parseTailFSFileExtensionForLog(req.URL.Path),
|
fileExtension: parseDriveFileExtensionForLog(req.URL.Path),
|
||||||
statusCode: resp.StatusCode,
|
statusCode: resp.StatusCode,
|
||||||
ReadCloser: resp.Body,
|
ReadCloser: resp.Body,
|
||||||
}
|
}
|
||||||
@ -4873,7 +4873,7 @@ func (t *tailFSTransport) RoundTrip(req *http.Request) (resp *http.Response, err
|
|||||||
// unreachable hosts.
|
// unreachable hosts.
|
||||||
dialTimeout := 1 * time.Second // TODO(oxtoacart): tune this
|
dialTimeout := 1 * time.Second // TODO(oxtoacart): tune this
|
||||||
|
|
||||||
tr := t.b.Dialer().PeerAPITransport().Clone()
|
tr := dt.b.Dialer().PeerAPITransport().Clone()
|
||||||
dialContext := tr.DialContext
|
dialContext := tr.DialContext
|
||||||
tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
ctxWithTimeout, cancel := context.WithTimeout(ctx, dialTimeout)
|
ctxWithTimeout, cancel := context.WithTimeout(ctx, dialTimeout)
|
||||||
|
@ -2295,12 +2295,12 @@ func TestTCPHandlerForDst(t *testing.T) {
|
|||||||
intercept: false,
|
intercept: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "intercept port 8080 (TailFS) on quad100 IPv4",
|
desc: "intercept port 8080 (Taildrive) on quad100 IPv4",
|
||||||
dst: "100.100.100.100:8080",
|
dst: "100.100.100.100:8080",
|
||||||
intercept: true,
|
intercept: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "intercept port 8080 (TailFS) on quad100 IPv6",
|
desc: "intercept port 8080 (Taildrive) on quad100 IPv6",
|
||||||
dst: "[fd7a:115c:a1e0::53]:8080",
|
dst: "[fd7a:115c:a1e0::53]:8080",
|
||||||
intercept: true,
|
intercept: true,
|
||||||
},
|
},
|
||||||
@ -2340,7 +2340,7 @@ func TestTCPHandlerForDst(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTailFSManageShares(t *testing.T) {
|
func TestDriveManageShares(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
disabled bool
|
disabled bool
|
||||||
@ -2410,7 +2410,7 @@ func TestTailFSManageShares(t *testing.T) {
|
|||||||
name: "add_disabled",
|
name: "add_disabled",
|
||||||
disabled: true,
|
disabled: true,
|
||||||
add: &drive.Share{Name: "a"},
|
add: &drive.Share{Name: "a"},
|
||||||
expect: ErrTailFSNotEnabled,
|
expect: ErrDriveNotEnabled,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "remove",
|
name: "remove",
|
||||||
@ -2439,7 +2439,7 @@ func TestTailFSManageShares(t *testing.T) {
|
|||||||
name: "remove_disabled",
|
name: "remove_disabled",
|
||||||
disabled: true,
|
disabled: true,
|
||||||
remove: "b",
|
remove: "b",
|
||||||
expect: ErrTailFSNotEnabled,
|
expect: ErrDriveNotEnabled,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "rename",
|
name: "rename",
|
||||||
@ -2480,7 +2480,7 @@ func TestTailFSManageShares(t *testing.T) {
|
|||||||
name: "rename_disabled",
|
name: "rename_disabled",
|
||||||
disabled: true,
|
disabled: true,
|
||||||
rename: [2]string{"a", "c"},
|
rename: [2]string{"a", "c"},
|
||||||
expect: ErrTailFSNotEnabled,
|
expect: ErrDriveNotEnabled,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2494,7 +2494,7 @@ func TestTailFSManageShares(t *testing.T) {
|
|||||||
b := newTestBackend(t)
|
b := newTestBackend(t)
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
if tt.existing != nil {
|
if tt.existing != nil {
|
||||||
b.tailFSSetSharesLocked(tt.existing)
|
b.driveSetSharesLocked(tt.existing)
|
||||||
}
|
}
|
||||||
if !tt.disabled {
|
if !tt.disabled {
|
||||||
self := b.netMap.SelfNode.AsStruct()
|
self := b.netMap.SelfNode.AsStruct()
|
||||||
@ -2517,7 +2517,7 @@ func TestTailFSManageShares(t *testing.T) {
|
|||||||
func() { wg.Done() },
|
func() { wg.Done() },
|
||||||
func(n *ipn.Notify) bool {
|
func(n *ipn.Notify) bool {
|
||||||
select {
|
select {
|
||||||
case result <- n.TailFSShares:
|
case result <- n.DriveShares:
|
||||||
default:
|
default:
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
@ -2529,11 +2529,11 @@ func(n *ipn.Notify) bool {
|
|||||||
var err error
|
var err error
|
||||||
switch {
|
switch {
|
||||||
case tt.add != nil:
|
case tt.add != nil:
|
||||||
err = b.TailFSSetShare(tt.add)
|
err = b.DriveSetShare(tt.add)
|
||||||
case tt.remove != "":
|
case tt.remove != "":
|
||||||
err = b.TailFSRemoveShare(tt.remove)
|
err = b.DriveRemoveShare(tt.remove)
|
||||||
default:
|
default:
|
||||||
err = b.TailFSRenameShare(tt.rename[0], tt.rename[1])
|
err = b.DriveRenameShare(tt.rename[0], tt.rename[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
switch e := tt.expect.(type) {
|
switch e := tt.expect.(type) {
|
||||||
|
@ -325,7 +325,7 @@ func (h *peerAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(r.URL.Path, tailFSPrefix) {
|
if strings.HasPrefix(r.URL.Path, tailFSPrefix) {
|
||||||
h.handleServeTailFS(w, r)
|
h.handleServeDrive(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
@ -1141,23 +1141,23 @@ func (rbw *requestBodyWrapper) Read(b []byte) (int, error) {
|
|||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *peerAPIHandler) handleServeTailFS(w http.ResponseWriter, r *http.Request) {
|
func (h *peerAPIHandler) handleServeDrive(w http.ResponseWriter, r *http.Request) {
|
||||||
if !h.ps.b.TailFSSharingEnabled() {
|
if !h.ps.b.DriveSharingEnabled() {
|
||||||
h.logf("tailfs: not enabled")
|
h.logf("tailfs: not enabled")
|
||||||
http.Error(w, "tailfs not enabled", http.StatusNotFound)
|
http.Error(w, "tailfs not enabled", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
capsMap := h.peerCaps()
|
capsMap := h.peerCaps()
|
||||||
tailfsCaps, ok := capsMap[tailcfg.PeerCapabilityTailFS]
|
driveCaps, ok := capsMap[tailcfg.PeerCapabilityTailFS]
|
||||||
if !ok {
|
if !ok {
|
||||||
h.logf("tailfs: not permitted")
|
h.logf("tailfs: not permitted")
|
||||||
http.Error(w, "tailfs not permitted", http.StatusForbidden)
|
http.Error(w, "tailfs not permitted", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rawPerms := make([][]byte, 0, len(tailfsCaps))
|
rawPerms := make([][]byte, 0, len(driveCaps))
|
||||||
for _, cap := range tailfsCaps {
|
for _, cap := range driveCaps {
|
||||||
rawPerms = append(rawPerms, []byte(cap))
|
rawPerms = append(rawPerms, []byte(cap))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1168,7 +1168,7 @@ func (h *peerAPIHandler) handleServeTailFS(w http.ResponseWriter, r *http.Reques
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fs, ok := h.ps.b.sys.TailFSForRemote.GetOK()
|
fs, ok := h.ps.b.sys.DriveForRemote.GetOK()
|
||||||
if !ok {
|
if !ok {
|
||||||
h.logf("tailfs: not supported on platform")
|
h.logf("tailfs: not supported on platform")
|
||||||
http.Error(w, "tailfs not supported on platform", http.StatusNotFound)
|
http.Error(w, "tailfs not supported on platform", http.StatusNotFound)
|
||||||
@ -1193,7 +1193,7 @@ func (h *peerAPIHandler) handleServeTailFS(w http.ResponseWriter, r *http.Reques
|
|||||||
contentType = ct
|
contentType = ct
|
||||||
}
|
}
|
||||||
|
|
||||||
h.logf("tailfs: share: %s from %s to %s: status-code=%d ext=%q content-type=%q tx=%.f rx=%.f", r.Method, h.peerNode.Key().ShortString(), h.selfNode.Key().ShortString(), wr.statusCode, parseTailFSFileExtensionForLog(r.URL.Path), contentType, roundTraffic(wr.contentLength), roundTraffic(bw.bytesRead))
|
h.logf("tailfs: share: %s from %s to %s: status-code=%d ext=%q content-type=%q tx=%.f rx=%.f", r.Method, h.peerNode.Key().ShortString(), h.selfNode.Key().ShortString(), wr.statusCode, parseDriveFileExtensionForLog(r.URL.Path), contentType, roundTraffic(wr.contentLength), roundTraffic(bw.bytesRead))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@ -1202,13 +1202,13 @@ func (h *peerAPIHandler) handleServeTailFS(w http.ResponseWriter, r *http.Reques
|
|||||||
fs.ServeHTTPWithPerms(p, wr, r)
|
fs.ServeHTTPWithPerms(p, wr, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseTailFSFileExtensionForLog parses the file extension, if available.
|
// parseDriveFileExtensionForLog parses the file extension, if available.
|
||||||
// If a file extension is not present or parsable, the file extension is
|
// If a file extension is not present or parsable, the file extension is
|
||||||
// set to "unknown". If the file extension contains a double quote, it is
|
// set to "unknown". If the file extension contains a double quote, it is
|
||||||
// replaced with "removed".
|
// replaced with "removed".
|
||||||
// All whitespace is removed from a parsed file extension.
|
// All whitespace is removed from a parsed file extension.
|
||||||
// File extensions including the leading ., e.g. ".gif".
|
// File extensions including the leading ., e.g. ".gif".
|
||||||
func parseTailFSFileExtensionForLog(path string) string {
|
func parseDriveFileExtensionForLog(path string) string {
|
||||||
fileExt := "unknown"
|
fileExt := "unknown"
|
||||||
if fe := filepath.Ext(path); fe != "" {
|
if fe := filepath.Ext(path); fe != "" {
|
||||||
if strings.Contains(fe, "\"") {
|
if strings.Contains(fe, "\"") {
|
||||||
|
@ -64,7 +64,7 @@ type serveHTTPContext struct {
|
|||||||
//
|
//
|
||||||
// This is not used in userspace-networking mode.
|
// This is not used in userspace-networking mode.
|
||||||
//
|
//
|
||||||
// localListener is used by tailscale serve (TCP only), the built-in web client and tailfs.
|
// localListener is used by tailscale serve (TCP only), the built-in web client and Taildrive.
|
||||||
// Most serve traffic and peer traffic for the web client are intercepted by netstack.
|
// Most serve traffic and peer traffic for the web client are intercepted by netstack.
|
||||||
// This listener exists purely for connections from the machine itself, as that goes via the kernel,
|
// This listener exists purely for connections from the machine itself, as that goes via the kernel,
|
||||||
// so we need to be in the kernel's listening/routing tables.
|
// so we need to be in the kernel's listening/routing tables.
|
||||||
|
@ -116,7 +116,7 @@
|
|||||||
"set-dns": (*Handler).serveSetDNS,
|
"set-dns": (*Handler).serveSetDNS,
|
||||||
"set-expiry-sooner": (*Handler).serveSetExpirySooner,
|
"set-expiry-sooner": (*Handler).serveSetExpirySooner,
|
||||||
"set-gui-visible": (*Handler).serveSetGUIVisible,
|
"set-gui-visible": (*Handler).serveSetGUIVisible,
|
||||||
"tailfs/fileserver-address": (*Handler).serveTailFSFileServerAddr,
|
"tailfs/fileserver-address": (*Handler).serveDriveServerAddr,
|
||||||
"tailfs/shares": (*Handler).serveShares,
|
"tailfs/shares": (*Handler).serveShares,
|
||||||
"start": (*Handler).serveStart,
|
"start": (*Handler).serveStart,
|
||||||
"status": (*Handler).serveStatus,
|
"status": (*Handler).serveStatus,
|
||||||
@ -2735,8 +2735,8 @@ func (h *Handler) serveUpdateProgress(w http.ResponseWriter, r *http.Request) {
|
|||||||
json.NewEncoder(w).Encode(ups)
|
json.NewEncoder(w).Encode(ups)
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveTailFSFileServerAddr handles updates of the tailfs file server address.
|
// serveDriveServerAddr handles updates of the Taildrive file server address.
|
||||||
func (h *Handler) serveTailFSFileServerAddr(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) serveDriveServerAddr(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method != "PUT" {
|
if r.Method != "PUT" {
|
||||||
http.Error(w, "only PUT allowed", http.StatusMethodNotAllowed)
|
http.Error(w, "only PUT allowed", http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
@ -2748,18 +2748,18 @@ func (h *Handler) serveTailFSFileServerAddr(w http.ResponseWriter, r *http.Reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.b.TailFSSetFileServerAddr(string(b))
|
h.b.DriveSetServerAddr(string(b))
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveShares handles the management of tailfs shares.
|
// serveShares handles the management of Taildrive shares.
|
||||||
//
|
//
|
||||||
// PUT - adds or updates an existing share
|
// PUT - adds or updates an existing share
|
||||||
// DELETE - removes a share
|
// DELETE - removes a share
|
||||||
// GET - gets a list of all shares, sorted by name
|
// GET - gets a list of all shares, sorted by name
|
||||||
// POST - renames an existing share
|
// POST - renames an existing share
|
||||||
func (h *Handler) serveShares(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) serveShares(w http.ResponseWriter, r *http.Request) {
|
||||||
if !h.b.TailFSSharingEnabled() {
|
if !h.b.DriveSharingEnabled() {
|
||||||
http.Error(w, `tailfs sharing not enabled, please add the attribute "tailfs:share" to this node in your ACLs' "nodeAttrs" section`, http.StatusForbidden)
|
http.Error(w, `tailfs sharing not enabled, please add the attribute "tailfs:share" to this node in your ACLs' "nodeAttrs" section`, http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2790,7 +2790,7 @@ func (h *Handler) serveShares(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
share.As = username
|
share.As = username
|
||||||
}
|
}
|
||||||
err = h.b.TailFSSetShare(&share)
|
err = h.b.DriveSetShare(&share)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ipnlocal.ErrInvalidShareName) {
|
if errors.Is(err, ipnlocal.ErrInvalidShareName) {
|
||||||
http.Error(w, "invalid share name", http.StatusBadRequest)
|
http.Error(w, "invalid share name", http.StatusBadRequest)
|
||||||
@ -2806,7 +2806,7 @@ func (h *Handler) serveShares(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = h.b.TailFSRemoveShare(string(b))
|
err = h.b.DriveRemoveShare(string(b))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
http.Error(w, "share not found", http.StatusNotFound)
|
http.Error(w, "share not found", http.StatusNotFound)
|
||||||
@ -2823,7 +2823,7 @@ func (h *Handler) serveShares(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = h.b.TailFSRenameShare(names[0], names[1])
|
err = h.b.DriveRenameShare(names[0], names[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
http.Error(w, "share not found", http.StatusNotFound)
|
http.Error(w, "share not found", http.StatusNotFound)
|
||||||
@ -2842,7 +2842,7 @@ func (h *Handler) serveShares(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
case "GET":
|
case "GET":
|
||||||
shares := h.b.TailFSGetShares()
|
shares := h.b.DriveGetShares()
|
||||||
err := json.NewEncoder(w).Encode(shares)
|
err := json.NewEncoder(w).Encode(shares)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -225,9 +225,9 @@ type Prefs struct {
|
|||||||
// Linux-only.
|
// Linux-only.
|
||||||
NetfilterKind string
|
NetfilterKind string
|
||||||
|
|
||||||
// TailFSShares are the configured TailFSShares, stored in increasing order
|
// DriveShares are the configured DriveShares, stored in increasing order
|
||||||
// by name.
|
// by name.
|
||||||
TailFSShares []*drive.Share
|
DriveShares []*drive.Share
|
||||||
|
|
||||||
// The Persist field is named 'Config' in the file for backward
|
// The Persist field is named 'Config' in the file for backward
|
||||||
// compatibility with earlier versions.
|
// compatibility with earlier versions.
|
||||||
@ -300,7 +300,7 @@ type MaskedPrefs struct {
|
|||||||
AppConnectorSet bool `json:",omitempty"`
|
AppConnectorSet bool `json:",omitempty"`
|
||||||
PostureCheckingSet bool `json:",omitempty"`
|
PostureCheckingSet bool `json:",omitempty"`
|
||||||
NetfilterKindSet bool `json:",omitempty"`
|
NetfilterKindSet bool `json:",omitempty"`
|
||||||
TailFSSharesSet bool `json:",omitempty"`
|
DriveSharesSet bool `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AutoUpdatePrefsMask struct {
|
type AutoUpdatePrefsMask struct {
|
||||||
@ -564,7 +564,7 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
|
|||||||
p.AutoUpdate.Equals(p2.AutoUpdate) &&
|
p.AutoUpdate.Equals(p2.AutoUpdate) &&
|
||||||
p.AppConnector == p2.AppConnector &&
|
p.AppConnector == p2.AppConnector &&
|
||||||
p.PostureChecking == p2.PostureChecking &&
|
p.PostureChecking == p2.PostureChecking &&
|
||||||
slices.EqualFunc(p.TailFSShares, p2.TailFSShares, drive.SharesEqual) &&
|
slices.EqualFunc(p.DriveShares, p2.DriveShares, drive.SharesEqual) &&
|
||||||
p.NetfilterKind == p2.NetfilterKind
|
p.NetfilterKind == p2.NetfilterKind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func TestPrefsEqual(t *testing.T) {
|
|||||||
"AppConnector",
|
"AppConnector",
|
||||||
"PostureChecking",
|
"PostureChecking",
|
||||||
"NetfilterKind",
|
"NetfilterKind",
|
||||||
"TailFSShares",
|
"DriveShares",
|
||||||
"Persist",
|
"Persist",
|
||||||
}
|
}
|
||||||
if have := fieldsOf(reflect.TypeFor[Prefs]()); !reflect.DeepEqual(have, prefsHandles) {
|
if have := fieldsOf(reflect.TypeFor[Prefs]()); !reflect.DeepEqual(have, prefsHandles) {
|
||||||
|
@ -1345,7 +1345,7 @@ type CapGrant struct {
|
|||||||
// PeerCapabilityWebUI grants the ability for a peer to edit features from the
|
// PeerCapabilityWebUI grants the ability for a peer to edit features from the
|
||||||
// device Web UI.
|
// device Web UI.
|
||||||
PeerCapabilityWebUI PeerCapability = "tailscale.com/cap/webui"
|
PeerCapabilityWebUI PeerCapability = "tailscale.com/cap/webui"
|
||||||
// PeerCapabilityTailFS grants the ability for a peer to access tailfs shares.
|
// PeerCapabilityTailFS grants the ability for a peer to access Taildrive shares.
|
||||||
PeerCapabilityTailFS PeerCapability = "tailscale.com/cap/tailfs"
|
PeerCapabilityTailFS PeerCapability = "tailscale.com/cap/tailfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,8 +48,8 @@ type System struct {
|
|||||||
Tun SubSystem[*tstun.Wrapper]
|
Tun SubSystem[*tstun.Wrapper]
|
||||||
StateStore SubSystem[ipn.StateStore]
|
StateStore SubSystem[ipn.StateStore]
|
||||||
Netstack SubSystem[NetstackImpl] // actually a *netstack.Impl
|
Netstack SubSystem[NetstackImpl] // actually a *netstack.Impl
|
||||||
TailFSForLocal SubSystem[drive.FileSystemForLocal]
|
DriveForLocal SubSystem[drive.FileSystemForLocal]
|
||||||
TailFSForRemote SubSystem[drive.FileSystemForRemote]
|
DriveForRemote SubSystem[drive.FileSystemForRemote]
|
||||||
|
|
||||||
// InitialConfig is initial server config, if any.
|
// InitialConfig is initial server config, if any.
|
||||||
// It is nil if the node is not in declarative mode.
|
// It is nil if the node is not in declarative mode.
|
||||||
@ -102,9 +102,9 @@ type ft interface {
|
|||||||
case NetstackImpl:
|
case NetstackImpl:
|
||||||
s.Netstack.Set(v)
|
s.Netstack.Set(v)
|
||||||
case drive.FileSystemForLocal:
|
case drive.FileSystemForLocal:
|
||||||
s.TailFSForLocal.Set(v)
|
s.DriveForLocal.Set(v)
|
||||||
case drive.FileSystemForRemote:
|
case drive.FileSystemForRemote:
|
||||||
s.TailFSForRemote.Set(v)
|
s.DriveForRemote.Set(v)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unknown type %T", v))
|
panic(fmt.Sprintf("unknown type %T", v))
|
||||||
}
|
}
|
||||||
|
@ -529,7 +529,7 @@ func (s *Server) start() (reterr error) {
|
|||||||
closePool.add(s.dialer)
|
closePool.add(s.dialer)
|
||||||
sys.Set(eng)
|
sys.Set(eng)
|
||||||
|
|
||||||
// TODO(oxtoacart): do we need to support TailFS on tsnet, and if so, how?
|
// TODO(oxtoacart): do we need to support Taildrive on tsnet, and if so, how?
|
||||||
ns, err := netstack.Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), s.dialer, sys.DNSManager.Get(), sys.ProxyMapper(), nil)
|
ns, err := netstack.Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), s.dialer, sys.DNSManager.Get(), sys.ProxyMapper(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("netstack.Create: %w", err)
|
return fmt.Errorf("netstack.Create: %w", err)
|
||||||
|
@ -189,7 +189,7 @@ type Impl struct {
|
|||||||
ctxCancel context.CancelFunc // called on Close
|
ctxCancel context.CancelFunc // called on Close
|
||||||
lb *ipnlocal.LocalBackend // or nil
|
lb *ipnlocal.LocalBackend // or nil
|
||||||
dns *dns.Manager
|
dns *dns.Manager
|
||||||
tailFSForLocal drive.FileSystemForLocal // or nil
|
driveForLocal drive.FileSystemForLocal // or nil
|
||||||
|
|
||||||
peerapiPort4Atomic atomic.Uint32 // uint16 port number for IPv4 peerapi
|
peerapiPort4Atomic atomic.Uint32 // uint16 port number for IPv4 peerapi
|
||||||
peerapiPort6Atomic atomic.Uint32 // uint16 port number for IPv6 peerapi
|
peerapiPort6Atomic atomic.Uint32 // uint16 port number for IPv6 peerapi
|
||||||
@ -248,7 +248,7 @@ type Impl struct {
|
|||||||
const maxUDPPacketSize = tstun.MaxPacketSize
|
const maxUDPPacketSize = tstun.MaxPacketSize
|
||||||
|
|
||||||
// Create creates and populates a new Impl.
|
// Create creates and populates a new Impl.
|
||||||
func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magicsock.Conn, dialer *tsdial.Dialer, dns *dns.Manager, pm *proxymap.Mapper, tailFSForLocal drive.FileSystemForLocal) (*Impl, error) {
|
func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magicsock.Conn, dialer *tsdial.Dialer, dns *dns.Manager, pm *proxymap.Mapper, driveForLocal drive.FileSystemForLocal) (*Impl, error) {
|
||||||
if mc == nil {
|
if mc == nil {
|
||||||
return nil, errors.New("nil magicsock.Conn")
|
return nil, errors.New("nil magicsock.Conn")
|
||||||
}
|
}
|
||||||
@ -330,7 +330,7 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi
|
|||||||
connsInFlightByClient: make(map[netip.Addr]int),
|
connsInFlightByClient: make(map[netip.Addr]int),
|
||||||
packetsInFlight: make(map[stack.TransportEndpointID]struct{}),
|
packetsInFlight: make(map[stack.TransportEndpointID]struct{}),
|
||||||
dns: dns,
|
dns: dns,
|
||||||
tailFSForLocal: tailFSForLocal,
|
driveForLocal: driveForLocal,
|
||||||
}
|
}
|
||||||
ns.ctx, ns.ctxCancel = context.WithCancel(context.Background())
|
ns.ctx, ns.ctxCancel = context.WithCancel(context.Background())
|
||||||
ns.atomicIsLocalIPFunc.Store(tsaddr.FalseContainsIPFunc())
|
ns.atomicIsLocalIPFunc.Store(tsaddr.FalseContainsIPFunc())
|
||||||
@ -670,7 +670,7 @@ func (ns *Impl) handleLocalPackets(p *packet.Parsed, t *tstun.Wrapper) filter.Re
|
|||||||
return filter.DropSilently
|
return filter.DropSilently
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's not traffic to the service IP (e.g. magicDNS or TailFS) we don't
|
// If it's not traffic to the service IP (e.g. magicDNS or Taildrive) we don't
|
||||||
// care; resume processing.
|
// care; resume processing.
|
||||||
if dst := p.Dst.Addr(); dst != serviceIP && dst != serviceIPv6 {
|
if dst := p.Dst.Addr(); dst != serviceIP && dst != serviceIPv6 {
|
||||||
return filter.Accept
|
return filter.Accept
|
||||||
|
@ -204,9 +204,9 @@ type Config struct {
|
|||||||
// SetSubsystem, if non-nil, is called for each new subsystem created, just before a successful return.
|
// SetSubsystem, if non-nil, is called for each new subsystem created, just before a successful return.
|
||||||
SetSubsystem func(any)
|
SetSubsystem func(any)
|
||||||
|
|
||||||
// TailFSForLocal, if populated, will cause the engine to expose a TailFS
|
// DriveForLocal, if populated, will cause the engine to expose a Taildrive
|
||||||
// listener at 100.100.100.100:8080.
|
// listener at 100.100.100.100:8080.
|
||||||
TailFSForLocal drive.FileSystemForLocal
|
DriveForLocal drive.FileSystemForLocal
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFakeUserspaceEngine returns a new userspace engine for testing.
|
// NewFakeUserspaceEngine returns a new userspace engine for testing.
|
||||||
@ -468,8 +468,8 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
|||||||
conf.SetSubsystem(conf.Router)
|
conf.SetSubsystem(conf.Router)
|
||||||
conf.SetSubsystem(conf.Dialer)
|
conf.SetSubsystem(conf.Dialer)
|
||||||
conf.SetSubsystem(e.netMon)
|
conf.SetSubsystem(e.netMon)
|
||||||
if conf.TailFSForLocal != nil {
|
if conf.DriveForLocal != nil {
|
||||||
conf.SetSubsystem(conf.TailFSForLocal)
|
conf.SetSubsystem(conf.DriveForLocal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user