836 Commits

Author SHA1 Message Date
Brad Fitzpatrick
c09cd34f59 ipn/ipnlocal: fix Taildrop deadlock
This fixes the Taildrop deadlock from 8b72dd787320.

Fixes #15824

Change-Id: I5ca583de20dd0d0b513ce546439dc632408ca1f1
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-04-30 21:21:37 -07:00
Nick Khyl
66371f392a feature,ipn/ipnlocal: add profileManager.StateChangeHook
We update profileManager to allow registering a single state (profile+prefs) change hook.
This is to invert the dependency between the profileManager and the LocalBackend, so that
instead of LocalBackend asking profileManager for the state, we can have profileManager
call LocalBackend when the state changes.

We also update feature.Hook with a new (*feature.Hook).GetOk method to avoid calling both
IsSet and Get.

Updates tailscale/corp#28014
Updates #12614

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-25 16:32:09 -05:00
Nick Khyl
8b72dd7873 ipn/ipnlocal: add localNodeContext with netmap-related fields and methods
Updates #12614

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-25 15:44:10 -05:00
Brad Fitzpatrick
3d8533b5d0 ipn/{ipnext,ipnlocal}: add a SafeBackend interface
Updates #12614

Change-Id: I197e673666e86ea74c19e3935ed71aec269b6c94
Co-authored-by: Nick Khyl <nickk@tailscale.com>
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-04-24 14:48:58 -07:00
Brad Fitzpatrick
0c78f081a4 feature/taildrop: start moving Taildrop out of LocalBackend
This adds a feature/taildrop package, a ts_omit_taildrop build tag,
and starts moving code to feature/taildrop. In some cases, code
remains where it was but is now behind a build tag. Future changes
will move code to an extension and out of LocalBackend, etc.

Updates #12614

Change-Id: Idf96c61144d1a5f707039ceb2ff59c99f5c1642f
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-04-16 15:57:59 -07:00
Nick Khyl
e6eba4efee ipn/{auditlog,ipnext,ipnlocal}: convert the profile-change callback to a profile-state-change callback
In this PR, we enable extensions to track changes in the current prefs. These changes can result from a profile switch
or from the user or system modifying the current profile’s prefs. Since some extensions may want to distinguish between
the two events, while others may treat them similarly, we rename the existing profile-change callback to become
a profile-state-change callback and invoke it whenever the current profile or its preferences change. Extensions can still
use the sameNode parameter to distinguish between situations where the profile information, including its preferences,
has been updated but still represents the same tailnet node, and situations where a switch to a different profile has been made.

Having dedicated prefs-change callbacks is being considered, but currently seems redundant. A single profile-state-change callback
is easier to maintain. We’ll revisit the idea of adding a separate callback as we progress on extracting existing features from LocalBackend,
but the conversion to a profile-state-change callback is intended to be permanent.

Finally, we let extensions retrieve the current prefs or profile state (profile info + prefs) at any time using the new
CurrentProfileState and CurrentPrefs methods. We also simplify the NewControlClientCallback signature to exclude
profile prefs. It’s optional, and extensions can retrieve the current prefs themselves if needed.

Updates #12614
Updates tailscale/corp#27645
Updates tailscale/corp#26435
Updates tailscale/corp#27502

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-15 15:08:04 -05:00
Jonathan Nobels
d6fd865d41
hostinfo, ipnlocal: add optional os-specific callback for querying the hostname (#15647)
updates tailscale/tailscale#13476

On darwin, os.Hostname is no longer reliable when called
from a sandboxed process.  To fix this, we will allow clients
to set an optional callback to query the hostname via an
alternative native API.

We will leave the default implementation as os.Hostname since
this works perfectly well for almost everything besides sandboxed
darwin clients.

Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
2025-04-14 15:02:32 -04:00
Nick Khyl
f28c8d0ec0 ipn/ipn{ext,local}: allow extension lookup by name or type
In this PR, we add two methods to facilitate extension lookup by both extensions,
and non-extensions (e.g., PeerAPI or LocalAPI handlers):
 - FindExtensionByName returns an extension with the specified name.
   It can then be type asserted to a given type.
 - FindMatchingExtension is like errors.As, but for extensions.
   It returns the first extension that matches the target type (either a specific extension
   or an interface).

Updates tailscale/corp#27645
Updates tailscale/corp#27502

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-11 18:34:46 -05:00
Nick Khyl
4941cd7c73 cmd/tailscaled,ipn/{auditlog,desktop,ipnext,ipnlocal},tsd: extract LocalBackend extension interfaces and implementation
In this PR, we refactor the LocalBackend extension system, moving from direct callbacks to a more organized extension host model.

Specifically, we:
- Extract interface and callback types used by packages extending LocalBackend functionality into a new ipn/ipnext package.
- Define ipnext.Host as a new interface that bridges extensions with LocalBackend.
  It enables extensions to register callbacks and interact with LocalBackend in a concurrency-safe, well-defined, and controlled way.
- Move existing callback registration and invocation code from ipnlocal.LocalBackend into a new type called ipnlocal.ExtensionHost,
  implementing ipnext.Host.
- Improve docs for existing types and methods while adding docs for the new interfaces.
- Add test coverage for both the extracted and the new code.
- Remove ipn/desktop.SessionManager from tsd.System since ipn/desktop is now self-contained.
- Update existing extensions (e.g., ipn/auditlog and ipn/desktop) to use the new interfaces where appropriate.

We're not introducing new callback and hook types (e.g., for ipn.Prefs changes) just yet, nor are we enhancing current callbacks,
such as by improving conflict resolution when more than one extension tries to influence profile selection via a background profile resolver.
These further improvements will be submitted separately.

Updates #12614
Updates tailscale/corp#27645
Updates tailscale/corp#26435
Updates tailscale/corp#18342

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-11 13:00:08 -05:00
Nick Khyl
94f4f83731 ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.

In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.

Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.

We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.

Updates tailscale/corp#27645
Updates tailscale/corp#18342

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-10 12:24:00 -05:00
kari-ts
5c562116fc
ipnlocal: log when client reports new peerAPI ports (#15463)
Updates tailscale/tailscale#14393

Signed-off-by: kari-ts <kari@tailscale.com>
2025-04-09 16:49:33 -07:00
Brad Fitzpatrick
bbdd3c3bde wgengine/router: add Plan 9 implementation
Updates #5794

Change-Id: Ib78a3ea971a2374d405b024ab88658ec34be59a6
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-04-02 07:36:04 -07:00
Percy Wegmann
a7be3a3d86 ipn/ipnlocal: add debug logging to initPeerAPIListener
initPeerAPIListener may be returning early unexpectedly. Add debug logging to
see what causes it to return early when it does.

Updates #14393

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-03-31 06:23:09 -05:00
Kristoffer Dalby
cdde301ca5 ipn/ipnlocal: return old hwaddrs if missing
If we previously knew of macaddresses of a node, and they
suddenly goes to zero, ignore them and return the previous
hardware addresses.

Updates tailscale/corp#25168

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2025-03-31 13:04:57 +02:00
Nick Khyl
6a9a7f35d9 cmd/tailscaled,ipn/{auditlog,ipnlocal},tsd: omit auditlog unless explicitly imported
In this PR, we update ipnlocal.LocalBackend to allow registering callbacks for control client creation
and profile changes. We also allow to register ipnauth.AuditLogFunc to be called when an auditable
action is attempted.

We then use all this to invert the dependency between the auditlog and ipnlocal packages and make
the auditlog functionality optional, where it only registers its callbacks via ipnlocal-provided hooks
when the auditlog package is imported.

We then underscore-import it when building tailscaled for Windows, and we'll explicitly
import it when building xcode/ipn-go-bridge for macOS. Since there's no default log-store
location for macOS, we'll also need to call auditlog.SetStoreFilePath to specify where
pending audit logs should be persisted.

Fixes #15394
Updates tailscale/corp#26435
Updates tailscale/corp#27012

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-03-28 10:36:49 -05:00
Nick Khyl
272854df41 ipn/ipnlocal: unconfigure wgengine when switching profiles
LocalBackend transitions to ipn.NoState when switching to a different (or new) profile.
When this happens, we should unconfigure wgengine to clear routes, DNS configuration,
firewall rules that block all traffic except to the exit node, etc.

In this PR, we update (*LocalBackend).enterStateLockedOnEntry to do just that.

Fixes #15316
Updates tailscale/corp#23967

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-03-28 10:31:45 -05:00
Jonathan Nobels
725c8d298a
ipn/ipnlocal: remove misleading [unexpected] log for auditlog (#15421)
fixes tailscale/tailscale#15394

In the current iteration, usage of the memstore for the audit
logger is expected on some platforms.

Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
2025-03-25 15:05:50 -04:00
Percy Wegmann
e78055eb01 ipn/ipnlocal: add more logging for initializing peerAPIListeners
On Windows and Android, peerAPIListeners may be initialized after a link change.
This commit adds log statements to make it easier to trace this flow.

Updates #14393

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-03-25 06:56:50 -05:00
Brad Fitzpatrick
14db99241f net/netmon: use Monitor's tsIfName if set by SetTailscaleInterfaceName
Currently nobody calls SetTailscaleInterfaceName yet, so this is a
no-op. I checked oss, android, and the macOS/iOS client. Nobody calls
this, or ever did.

But I want to in the future.

Updates #15408
Updates #9040

Change-Id: I05dfabe505174f9067b929e91c6e0d8bc42628d7
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-03-24 13:34:02 -07:00
Brad Fitzpatrick
d0c50c6072 clientupdate: cache CanAutoUpdate, avoid log spam when false
I noticed logs on one of my machines where it can't auto-update with
scary log spam about "failed to apply tailnet-wide default for
auto-updates".

This avoids trying to do the EditPrefs if we know it's just going to
fail anyway.

Updates #282

Change-Id: Ib7db3b122185faa70efe08b60ebd05a6094eed8c
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-03-24 09:46:48 -07:00
Nick Khyl
f3f2f72f96 ipn/ipnlocal: do not attempt to start the auditlogger with a nil transport
(*LocalBackend).setControlClientLocked() is called to both set and reset b.cc.
We shouldn't attempt to start the audit logger when b.cc is being reset (i.e., cc is nil).

However, it's fine to start the audit logger if b.cc implements auditlog.Transport, even if it's not a controlclient.Auto but a mock control client.

In this PR, we fix both issues and add an assertion that controlclient.Auto is an auditlog.Transport. This ensures a compile-time failure if controlclient.Auto ever stops being a valid transport due to future interface or implementation changes.

Updates tailscale/corp#26435

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-03-20 15:56:54 -05:00
Nick Khyl
e07c1573f6 ipn/ipnlocal: do not reset the netmap and packet filter in (*LocalBackend).Start()
Resetting LocalBackend's netmap without also unconfiguring wgengine to reset routes, DNS, and the killswitch
firewall rules may cause connectivity issues until a new netmap is received.

In some cases, such as when bootstrap DNS servers are inaccessible due to network restrictions or other reasons,
or if the control plane is experiencing issues, this can result in a complete loss of connectivity until the user disconnects
and reconnects to Tailscale.

As LocalBackend handles state resets in (*LocalBackend).resetForProfileChangeLockedOnEntry(), and this includes
resetting the netmap, resetting the current netmap in (*LocalBackend).Start() is not necessary.
Moreover, it's harmful if (*LocalBackend).Start() is called more than once for the same profile.

In this PR, we update resetForProfileChangeLockedOnEntry() to reset the packet filter and remove
the redundant resetting of the netmap and packet filter from Start(). We also update the state machine
tests and revise comments that became inaccurate due to previous test updates.

Updates tailscale/corp#27173

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-03-20 13:18:23 -05:00
Jonathan Nobels
52710945f5
control/controlclient, ipn: add client audit logging (#14950)
updates tailscale/corp#26435

Adds client support for sending audit logs to control via /machine/audit-log.
Specifically implements audit logging for user initiated disconnections.

This will require further work to optimize the peristant storage and exclusion
via build tags for mobile:
tailscale/corp#27011
tailscale/corp#27012

Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
2025-03-12 10:37:03 -04:00
Naman Sood
a4b8c24834
ipn: sort VIP services before hashing (#15035)
We're computing the list of services to hash by iterating over the
values of a map, the ordering of which is not guaranteed. This can cause
the hash to fluctuate depending on the ordering if there's more than one
service hosted by the same host.

Updates tailscale/corp#25733.

Signed-off-by: Naman Sood <mail@nsood.in>
2025-03-07 12:50:15 -05:00
Percy Wegmann
ce6ce81311 ipn/ipnlocal: initialize Taildrive shares when starting backend
Previously, it initialized when the backend was created. This caused two problems:

1. It would not properly switch when changing profiles.
2. If the backend was created before the profile had been selected, Taildrive's shares were uninitialized.

Updates #14825

Signed-off-by: Percy Wegmann <percy@tailscale.com>
2025-03-03 12:56:35 -06:00
kari-ts
dc18091678
ipn: update AddPeer to include TaildropTarget (#15091)
We previously were not merging in the TaildropTarget into the PeerStatus because we did not update AddPeer.

Updates tailscale/tailscale#14393

Signed-off-by: kari-ts <kari@tailscale.com>
2025-02-28 14:17:28 -08:00
KevinLiang10
8c2717f96a
ipn/ipnlocal: send vipServices info via c2n even it's incomplete (#15166)
This commit updates the logic of vipServicesFromPrefsLocked, so that it would return the vipServices list
even when service host is only advertising the service but not yet serving anything. This makes control
always get accurate state of service host in terms of serving a service.

Fixes tailscale/corp#26843

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>
2025-02-28 13:51:07 -05:00
Nick Khyl
8d7033fe7f ipn/ipnlocal,util/syspolicy,docs/windows/policy: implement the ReconnectAfter policy setting
In this PR, we update the LocalBackend so that when the ReconnectAfter policy setting is configured
and a user disconnects Tailscale by setting WantRunning to false in the profile prefs, the LocalBackend
will now start a timer to set WantRunning back to true once the ReconnectAfter timer expires.

We also update the ADMX/ADML policy definitions to allow configuring this policy setting for Windows
via Group Policy and Intune.

Updates #14824

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-24 17:07:19 -06:00
Nick Khyl
09982e1918 ipn/ipnlocal: reset always-on override and apply policy settings on start
We already reset the always-on override flag when switching profiles and in a few other cases.
In this PR, we update (*LocalBackend).Start() to reset it as well. This is necessary to support
scenarios where Start() is called explicitly, such as when the GUI starts or when tailscale up is used
with additional flags and passes prefs via ipn.Options in a call to Start() rather than via EditPrefs.

Additionally, we update it to apply policy settings to the current prefs, which is necessary
for properly overriding prefs specified in ipn.Options.

Updates #14823

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-18 16:49:25 -06:00
Irbe Krumina
b21eec7621
ipn/ipnlocal,tailcfg: don't send WireIngress if IngressEnabled already true (#14960)
Hostinfo.WireIngress is used as a hint that the node intends to use
funnel. We now send another field, IngressEnabled, in cases where
funnel is explicitly enabled, and the logic control-side has
been changed to look at IngressEnabled as well as WireIngress in all
cases where previously the hint was used - so we can now stop sending
WireIngress when IngressEnabled is true to save some bandwidth.

Updates tailscale/tailscale#11572
Updates tailscale/corp#25931

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
2025-02-16 09:38:02 +00:00
Nick Khyl
6df5c8f32e various: keep tailscale connected when Always On mode is enabled on Windows
In this PR, we enable the registration of LocalBackend extensions to exclude code specific to certain
platforms or environments. We then introduce desktopSessionsExt, which is included only in Windows builds
and only if the ts_omit_desktop_sessions tag is disabled for the build. This extension tracks desktop sessions
and switches to (or remains on) the appropriate profile when a user signs in or out, locks their screen,
or disconnects a remote session.

As desktopSessionsExt requires an ipn/desktop.SessionManager, we register it with tsd.System
for the tailscaled subprocess on Windows.

We also fix a bug in the sessionWatcher implementation where it attempts to close a nil channel on stop.

Updates #14823
Updates tailscale/corp#26247

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-14 16:40:54 -06:00
kari-ts
4c3c04a413
ipn, tailscale/cli: add TaildropTargetStatus and remove race with FileTargets (#15017)
Introduce new TaildropTargetStatus in PeerStatus
Refactor getTargetStableID to solely rely on Status() instead of calling FileTargets(). This removes a possible race condition between the two calls and provides more detailed failure information if a peer can't receive files.

Updates tailscale/tailscale#14393

Signed-off-by: kari-ts <kari@tailscale.com>
2025-02-14 09:56:50 -08:00
James 'zofrex' Sanderson
e142571397
ipn/ipnlocal: add GetFilterForTest (#15025)
Needed to test full packet filter in e2e tests. See tailscale/corp#26596

Updates tailscale/corp#20514

Signed-off-by: James Sanderson <jsanderson@tailscale.com>
2025-02-14 15:25:48 +00:00
Nick Khyl
7aef4fd44d ipn/ipn{local,server}: extract logic that determines the "best" Tailscale profile to use
In this PR, we further refactor LocalBackend and Unattended Mode to extract the logic that determines
which profile should be used at the time of the check, such as when a LocalAPI client connects or disconnects.
We then update (*LocalBackend).switchProfileLockedOnEntry to to switch to the profile returned by
(*LocalBackend).resolveBestProfileLocked() rather than to the caller-specified specified profile, and rename it
to switchToBestProfileLockedOnEntry.

This is done in preparation for updating (*LocalBackend).getBackgroundProfileIDLocked to support Always-On
mode by determining which profile to use based on which users, if any, are currently logged in and have an active
foreground desktop session.

Updates #14823
Updates tailscale/corp#26247

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-12 19:06:40 -06:00
Nick Khyl
9b32ba7f54 ipn/ipn{local,server}: move "staying alive in server mode" from ipnserver to LocalBackend
Currently, we disconnect Tailscale and reset LocalBackend on Windows when the last LocalAPI client
disconnects, unless Unattended Mode is enabled for the current profile. And the implementation
is somewhat racy since the current profile could theoretically change after
(*ipnserver.Server).addActiveHTTPRequest checks (*LocalBackend).InServerMode() and before it calls
(*LocalBackend).SetCurrentUser(nil) (or, previously, (*LocalBackend).ResetForClientDisconnect).

Additionally, we might want to keep Tailscale running and connected while a user is logged in
rather than tying it to whether a LocalAPI client is connected (i.e., while the GUI is running),
even when Unattended Mode is disabled for a profile. This includes scenarios where the new
AlwaysOn mode is enabled, as well as when Tailscale is used on headless Windows editions,
such as Windows Server Core, where the GUI is not supported. It may also be desirable to switch
to the "background" profile when a user logs off from their device or implement other similar
features.

To facilitate these improvements, we move the logic from ipnserver.Server to ipnlocal.LocalBackend,
where it determines whether to keep Tailscale running when the current user disconnects.
We also update the logic that determines whether a connection should be allowed to better reflect
the fact that, currently, LocalAPI connections are not allowed unless:
 - the current UID is "", meaning that either we are not on a multi-user system or Tailscale is idle;
 - the LocalAPI client belongs to the current user (their UIDs are the same);
 - the LocalAPI client is Local System (special case; Local System is always allowed).
Whether Unattended Mode is enabled only affects the error message returned to the Local API client
when the connection is denied.

Updates #14823

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-11 15:58:06 -06:00
Brad Fitzpatrick
9706c9f4ff types/netmap,*: pass around UserProfiles as views (pointers) instead
Smaller.

Updates tailscale/corp#26058 (@andrew-d noticed during this)

Change-Id: Id33cddd171aaf8f042073b6d3c183b0a746e9931
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-02-11 07:12:54 -08:00
Nick Khyl
48dd4bbe21 ipn/ipn{local,server}: remove ResetForClientDisconnect in favor of SetCurrentUser(nil)
There’s (*LocalBackend).ResetForClientDisconnect, and there’s also (*LocalBackend).resetForProfileChangeLockedOnEntry.
Both methods essentially did the same thing but in slightly different ways. For example, resetForProfileChangeLockedOnEntry didn’t reset the control client until (*LocalBackend).Start() was called at the very end and didn’t reset the keyExpired flag, while ResetForClientDisconnect didn’t reinitialize TKA.

Since SetCurrentUser can be called with a nil argument to reset the currently connected user and internally calls resetForProfileChangeLockedOnEntry, we can remove ResetForClientDisconnect and let SetCurrentUser and resetForProfileChangeLockedOnEntry handle it.

Updates #14823

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-10 14:54:14 -06:00
Nick Khyl
00fe8845b1 ipn/{ipnauth,ipnlocal,ipnserver}: move the AlwaysOn policy check from ipnserver to ipnauth
In this PR, we move the code that checks the AlwaysOn policy from ipnserver.actor to ipnauth.
It is intended to be used by ipnauth.Actor implementations, and we temporarily make it exported
while these implementations reside in ipnserver and in corp. We'll unexport it later.

We also update [ipnauth.Actor.CheckProfileAccess] to accept an auditLogger, which is called
to write details about the action to the audit log when required by the policy, and update
LocalBackend.EditPrefsAs to use an auditLogger that writes to the regular backend log.

Updates tailscale/corp#26146

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-04 14:36:01 -06:00
Adrian Dewhurst
97c4c0ecf0 ipn/ipnlocal: add VIP service IPs to localnets
Without adding this, the packet filter rejects traffic to VIP service
addresses before checking the filters sent in the netmap.

Fixes tailscale/corp#26241

Change-Id: Idd54448048e9b786cf4873fd33b3b21e03d3ad4c
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
2025-02-03 15:34:19 -05:00
Adrian Dewhurst
600f25dac9 tailcfg: add JSON unmarshal helper for view of node/peer capabilities
Many places that need to work with node/peer capabilities end up with a
something-View and need to either reimplement the helper code or make an
expensive copy. We have the machinery to easily handle this now.

Updates #cleanup

Change-Id: Ic3f55be329f0fc6c178de26b34359d0e8c6ca5fc
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
2025-02-03 14:49:11 -05:00
Nick Khyl
d832467461 client/tailscale,ipn/ipn{local,server},util/syspolicy: implement the AlwaysOn.OverrideWithReason policy setting
In this PR, we update client/tailscale.LocalClient to allow sending requests with an optional X-Tailscale-Reason
header. We then update ipn/ipnserver.{actor,Server} to retrieve this reason, if specified, and use it to determine
whether ipnauth.Disconnect is allowed when the AlwaysOn.OverrideWithReason policy setting is enabled.
For now, we log the reason, along with the profile and OS username, to the backend log.

Finally, we update LocalBackend to remember when a disconnect was permitted and do not reconnect automatically
unless the policy changes.

Updates tailscale/corp#26146

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-01 13:34:45 -06:00
Nick Khyl
a0537dc027 ipn/ipnlocal: fix a panic in setPrefsLockedOnEntry when cc is nil
The AlwaysOn policy can be applied by (*LocalBackend).applySysPolicy, flipping WantRunning from false to true
before (*LocalBackend).Start() has been called for the first time and set a control client in b.cc. This results in a nil
pointer dereference and a panic when setPrefsLockedOnEntry applies the change and calls controlclient.Client.Login().

In this PR, we fix it by only doing a login if b.cc has been set.

Updates #14823

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-31 18:41:02 -06:00
Nick Khyl
02ad21717f ipn/ipn{auth,server,local}: initial support for the always-on mode
In this PR, we update LocalBackend to set WantRunning=true when applying policy settings
to the current profile's prefs, if the "always-on" mode is enabled.

We also implement a new (*LocalBackend).EditPrefsAs() method, which is like EditPrefs
but accepts an actor (e.g., a LocalAPI client's identity) that initiated the change.
If WantRunning is being set to false, the new EditPrefsAs method checks whether the actor
has ipnauth.Disconnect access to the profile and propagates an error if they do not.

Finally, we update (*ipnserver.actor).CheckProfileAccess to allow a disconnect
only if the "always-on" mode is not enabled by the AlwaysOn policy setting.

This is not a comprehensive solution to the "always-on" mode across platforms,
as instead of disconnecting a user could achieve the same effect by creating
a new empty profile, initiating a reauth, or by deleting the profile.
These are the things we should address in future PRs.

Updates #14823

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-31 10:22:20 -06:00
Nick Khyl
4e7f4086b2 ipn: generate LoginProfileView and use it instead of *LoginProfile where appropriate
Conventionally, we use views (e.g., ipn.PrefsView, tailcfg.NodeView, etc.) when
dealing with structs that shouldn't be mutated. However, ipn.LoginProfile has been
an exception so far, with a mix of passing and returning LoginProfile by reference
(allowing accidental mutations) and by value (which is wasteful, given its
current size of 192 bytes).

In this PR, we generate an ipn.LoginProfileView and use it instead of passing/returning
LoginProfiles by mutable reference or copying them when passing/returning by value.
Now, LoginProfiles can only be mutated by (*profileManager).setProfilePrefs.

Updates #14823

Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-30 18:12:54 -06:00
Brad Fitzpatrick
ba1f9a3918 types/persist: remove Persist.LegacyFrontendPrivateMachineKey
It was a temporary migration over four years ago. It's no longer
relevant.

Updates #610

Change-Id: I1f00c9485fab13ede6f77603f7d4235222c2a481
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-01-27 22:01:50 +00:00
Brad Fitzpatrick
68a66ee81b feature/capture: move packet capture to feature/*, out of iOS + CLI
We had the debug packet capture code + Lua dissector in the CLI + the
iOS app. Now we don't, with tests to lock it in.

As a bonus, tailscale.com/net/packet and tailscale.com/net/flowtrack
no longer appear in the CLI's binary either.

A new build tag ts_omit_capture disables the packet capture code and
was added to build_dist.sh's --extra-small mode.

Updates #12614

Change-Id: I79b0628c0d59911bd4d510c732284d97b0160f10
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-01-24 17:52:43 -08:00
Andrew Lytvynov
f1710f4a42
appc,ipn/ipnlocal: log DNS parsing errors in app connectors (#14607)
If we fail to parse the upstream DNS response in an app connector, we
might miss new IPs for the target domain. Log parsing errors to be able
to diagnose that.

Updates #14606

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
2025-01-23 09:03:56 -08:00
Andrew Lytvynov
3fb8a1f6bf
ipn/ipnlocal: re-advertise appc routes on startup, take 2 (#14740)
* Reapply "ipn/ipnlocal: re-advertise appc routes on startup (#14609)"

This reverts commit 51adaec35a3e4d25df88d81e6264584e151bd33d.

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>

* ipn/ipnlocal: fix a deadlock in readvertiseAppConnectorRoutes

Don't hold LocalBackend.mu while calling the methods of
appc.AppConnector. Those methods could call back into LocalBackend and
try to acquire it's mutex.

Fixes https://github.com/tailscale/corp/issues/25965
Fixes #14606

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>

---------

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
2025-01-22 16:50:25 -08:00
Adrian Dewhurst
0fa7b4a236 tailcfg: add ServiceName
Rather than using a string everywhere and needing to clarify that the
string should have the svc: prefix, create a separate type for Service
names.

Updates tailscale/corp#24607

Change-Id: I720e022f61a7221644bb60955b72cacf42f59960
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
2025-01-22 15:27:46 -05:00
KevinLiang10
550923d953 fix handler related and some nit
Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>
2025-01-22 11:02:26 -05:00