Update
This commit is contained in:
1 parent
3530afb854
commit
6903fcff27
2146 files changed
+112256
-190703
No files matched your search
+107
-72
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ts_omit_drive
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"os"
|
||||
@@ -16,22 +17,43 @@ import (
|
||||
|
||||
"tailscale.com/drive"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/tailcfg/peercap"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/types/views"
|
||||
"tailscale.com/util/httpm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
hookSetNetMapLockedDrive.Set(setNetMapLockedDrive)
|
||||
hookInstallDriveRemoteSource.Set(installDriveRemoteSource)
|
||||
}
|
||||
|
||||
func setNetMapLockedDrive(b *LocalBackend, nm *netmap.NetworkMap) {
|
||||
b.updateDrivePeersLocked(nm)
|
||||
// setNetMapLockedDrive runs on every full netmap install (the only path that
|
||||
// can flip self caps or change the tailnet domain) to re-notify IPN bus
|
||||
// listeners of the current local shares.
|
||||
//
|
||||
// It deliberately does NOT touch the remotes list passed to the local drive
|
||||
// filesystem: that flows through [driveRemoteSource], which the filesystem
|
||||
// pulls from lazily and only when something might have changed. See
|
||||
// [LocalBackend.driveGen].
|
||||
func setNetMapLockedDrive(b *LocalBackend) {
|
||||
b.driveNotifyCurrentSharesLocked()
|
||||
}
|
||||
|
||||
// installDriveRemoteSource registers a [drive.RemoteSource] on the local
|
||||
// Taildrive filesystem so it can pull the current set of remotes on demand
|
||||
// instead of being pushed a fresh list on every netmap update.
|
||||
//
|
||||
// It is wired from [NewLocalBackend] via [hookInstallDriveRemoteSource] so
|
||||
// non-drive builds don't reference the drive package at all.
|
||||
func installDriveRemoteSource(b *LocalBackend) {
|
||||
fs, ok := b.sys.DriveForLocal.GetOK()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
fs.SetRemoteSource(driveRemoteSource{b})
|
||||
}
|
||||
|
||||
// DriveSetServerAddr tells Taildrive to use the given address for connecting
|
||||
// to the drive.FileServer that's exposing local files as an unprivileged
|
||||
// user.
|
||||
@@ -285,80 +307,93 @@ func (b *LocalBackend) DriveGetShares() views.SliceView[*drive.Share, drive.Shar
|
||||
return b.pm.prefs.DriveShares()
|
||||
}
|
||||
|
||||
// updateDrivePeersLocked sets all applicable peers from the netmap as Taildrive
|
||||
// remotes.
|
||||
func (b *LocalBackend) updateDrivePeersLocked(nm *netmap.NetworkMap) {
|
||||
fs, ok := b.sys.DriveForLocal.GetOK()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// driveRemoteSource implements [drive.RemoteSource] by reading from a
|
||||
// [LocalBackend]. It is installed once on the local Taildrive filesystem
|
||||
// at [NewLocalBackend] time and consulted lazily on incoming WebDAV
|
||||
// requests.
|
||||
//
|
||||
// The filesystem only rebuilds its internal child list when [Generation]
|
||||
// changes, so peer churn that doesn't affect the drive-capable peer set
|
||||
// (e.g. endpoint or online-status mutations on non-drive peers) costs
|
||||
// nothing more than a single atomic load.
|
||||
type driveRemoteSource struct{ b *LocalBackend }
|
||||
|
||||
var driveRemotes []*drive.Remote
|
||||
if b.DriveAccessEnabled() {
|
||||
// Only populate peers if access is enabled, otherwise leave blank.
|
||||
driveRemotes = b.driveRemotesFromPeers(nm)
|
||||
}
|
||||
|
||||
fs.SetRemotes(nm.Domain, driveRemotes, b.newDriveTransport())
|
||||
// Generation implements [drive.RemoteSource].
|
||||
func (s driveRemoteSource) Generation() uint64 {
|
||||
return s.b.driveGen.Load()
|
||||
}
|
||||
|
||||
func (b *LocalBackend) driveRemotesFromPeers(nm *netmap.NetworkMap) []*drive.Remote {
|
||||
b.logf("[v1] taildrive: setting up drive remotes from peers")
|
||||
driveRemotes := make([]*drive.Remote, 0, len(nm.Peers))
|
||||
for _, p := range nm.Peers {
|
||||
peer := p
|
||||
peerID := peer.ID()
|
||||
peerKey := peer.Key().ShortString()
|
||||
b.logf("[v1] taildrive: appending remote for peer %s", peerKey)
|
||||
driveRemotes = append(driveRemotes, &drive.Remote{
|
||||
Name: p.DisplayName(false),
|
||||
URL: func() string {
|
||||
url := fmt.Sprintf("%s/%s", b.currentNode().PeerAPIBase(peer), taildrivePrefix[1:])
|
||||
b.logf("[v2] taildrive: url for peer %s: %s", peerKey, url)
|
||||
return url
|
||||
},
|
||||
Available: func() bool {
|
||||
// Peers are available to Taildrive if:
|
||||
// - They are online
|
||||
// - Their PeerAPI is reachable
|
||||
// - They are allowed to share at least one folder with us
|
||||
cn := b.currentNode()
|
||||
peer, ok := cn.NodeByID(peerID)
|
||||
if !ok {
|
||||
b.logf("[v2] taildrive: Available(): peer %s not found", peerKey)
|
||||
return false
|
||||
}
|
||||
// Domain implements [drive.RemoteSource].
|
||||
func (s driveRemoteSource) Domain() string {
|
||||
nm := s.b.currentNode().NetMap()
|
||||
if nm == nil {
|
||||
return ""
|
||||
}
|
||||
return nm.Domain
|
||||
}
|
||||
|
||||
// Exclude offline peers.
|
||||
// TODO(oxtoacart): for some reason, this correctly
|
||||
// catches when a node goes from offline to online,
|
||||
// but not the other way around...
|
||||
// TODO(oxtoacart,nickkhyl): the reason was probably
|
||||
// that we were using netmap.Peers instead of b.peers.
|
||||
// The netmap.Peers slice is not updated in all cases.
|
||||
// It should be fixed now that we use PeerByIDOk.
|
||||
if !peer.Online().Get() {
|
||||
b.logf("[v2] taildrive: Available(): peer %s offline", peerKey)
|
||||
return false
|
||||
}
|
||||
// Transport implements [drive.RemoteSource].
|
||||
func (s driveRemoteSource) Transport() http.RoundTripper {
|
||||
return s.b.newDriveTransport()
|
||||
}
|
||||
|
||||
if b.currentNode().PeerAPIBase(peer) == "" {
|
||||
b.logf("[v2] taildrive: Available(): peer %s PeerAPI unreachable", peerKey)
|
||||
// Remotes implements [drive.RemoteSource]. It yields one [*drive.Remote]
|
||||
// per peer; the per-Remote Available closure filters out peers that
|
||||
// aren't online, don't expose PeerAPI, or haven't granted us the
|
||||
// Taildrive sharer cap. If drive access is disabled on this node, no
|
||||
// remotes are yielded at all, so the filesystem ends up with an empty
|
||||
// child list.
|
||||
func (s driveRemoteSource) Remotes() iter.Seq[*drive.Remote] {
|
||||
return func(yield func(*drive.Remote) bool) {
|
||||
b := s.b
|
||||
if !b.DriveAccessEnabled() {
|
||||
return
|
||||
}
|
||||
cn := b.currentNode()
|
||||
peers := cn.Peers()
|
||||
b.logf("[v1] taildrive: building drive remotes from %d peers", len(peers))
|
||||
for _, peer := range peers {
|
||||
peerID := peer.ID()
|
||||
peerKey := peer.Key().ShortString()
|
||||
peerName := peer.DisplayName(false)
|
||||
r := &drive.Remote{
|
||||
Name: peerName,
|
||||
URL: func() string {
|
||||
url := fmt.Sprintf("%s/%s", cn.PeerAPIBase(peer), taildrivePrefix[1:])
|
||||
b.logf("[v2] taildrive: url for peer %s (%s): %s", peerKey, peerName, url)
|
||||
return url
|
||||
},
|
||||
Available: func() bool {
|
||||
// Peers are available to Taildrive if:
|
||||
// - They are online
|
||||
// - Their PeerAPI is reachable
|
||||
// - They are allowed to share at least one folder with us
|
||||
peer, ok := cn.NodeByID(peerID)
|
||||
if !ok {
|
||||
b.logf("[v2] taildrive: peer %s (%s, id=%v) not found", peerKey, peerName, peerID)
|
||||
return false
|
||||
}
|
||||
if !peer.Online().Get() {
|
||||
b.logf("[v2] taildrive: peer %s (%s, id=%v) offline", peerKey, peerName, peerID)
|
||||
return false
|
||||
}
|
||||
if cn.PeerAPIBase(peer) == "" {
|
||||
b.logf("[v2] taildrive: peer %s (%s, id=%v) PeerAPI unreachable", peerKey, peerName, peerID)
|
||||
return false
|
||||
}
|
||||
if cn.PeerHasCap(peer, peercap.TaildriveSharer) {
|
||||
b.logf("[v2] taildrive: peer %s (%s, id=%v) available", peerKey, peerName, peerID)
|
||||
return true
|
||||
}
|
||||
b.logf("[v2] taildrive: peer %s (%s, id=%v) not allowed to share", peerKey, peerName, peerID)
|
||||
return false
|
||||
}
|
||||
|
||||
// Check that the peer is allowed to share with us.
|
||||
if cn.PeerHasCap(peer, tailcfg.PeerCapabilityTaildriveSharer) {
|
||||
b.logf("[v2] taildrive: Available(): peer %s available", peerKey)
|
||||
return true
|
||||
}
|
||||
|
||||
b.logf("[v2] taildrive: Available(): peer %s not allowed to share", peerKey)
|
||||
return false
|
||||
},
|
||||
})
|
||||
},
|
||||
}
|
||||
if !yield(r) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return driveRemotes
|
||||
}
|
||||
|
||||
// responseBodyWrapper wraps an io.ReadCloser and stores
|
||||
|
||||
Reference in new issue
Block a user