Commit Graph
245 Commits
Author SHA1 Message Date
Adriano Sela AvilesandAdriano Sela Aviles d69bf2685a all: apply go fix
Updates #cleanup

Signed-off-by: Adriano Sela Aviles <adriano@tailscale.com>
2026-07-10 17:39:16 -07:00
Brad FitzpatrickandBrad Fitzpatrick ac84eb4900 ipn/ipnlocal: pass self node view to reconfigAppConnectorLocked
The netmap.NetworkMap type is deprecated and going away, and
reconfigAppConnectorLocked only needed its SelfNode field anyway.
Take a tailcfg.NodeView instead and check its validity in place of
the old nil netmap check.

Updates #12542

Change-Id: Id617845b67416404500cca438ce4ac0372cd8a8e
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-07-09 15:04:59 -07:00
Alex ChanandAlex Chan b838d5caf7 all: fix typos where we repeat repeat ourselves
Found with the regex `\b([A-Za-z]+) \1\b`.

Updates #cleanup

Change-Id: I4cc51784d9b6437d3d0c66b531828707f87f7fd5
Signed-off-by: Alex Chan <alexc@tailscale.com>
2026-07-03 16:09:03 +01:00
Simon LawandSimon Law 932260511e ipn/ipnlocal: use routecheck reports to make exit node suggestions
Now that the routecheck subsystem is continuously collecting
reachability reports in the background, we can add a hook to
LocalBackend for fetching its report. That allows
suggestExitNodeUsingTrafficSteering to consult that report when
disqualifying candidates, instead of blocking on an immediate probe.

Exit node suggestions will only consult the report when the
`client-side-reachability` and `client-side-reachability-routecheck`
node attributes are both set on the current node.

Updates #17366
Updates tailscale/corp#33033

Signed-off-by: Simon Law <sfllaw@tailscale.com>
2026-07-02 20:26:27 -07:00
kari-tsandGitHub 07cefc083d ipn/{ipn,ipnlocal}: add per-user policy snapshots to IPN bus (#20135)
This adds the NotifyInitialPolicy watch option and the Policy field in
Notify so that clients can receive the effective policy snapshot via IPN
bus.

This extends policyclient.Client so ipnlocal can get and watch policy
snapshots, which is used by sysPolicyChanged to notify watchers.

User-scoped policy store registration, management, and cleanup will be
added in a follow-up

Updates tailscale/corp#42259

Signed-off-by: kari <kari@tailscale.com>
2026-06-30 12:44:29 -07:00
Brad FitzpatrickandBrad Fitzpatrick 4bb6f35c1f ipn/ipnlocal: consolidate test-only LocalBackend methods behind ForTest
Move all the FooForTest methods on LocalBackend to instead be
methods on a new unexported forTest type which is then given out
to callers in other packages via an exported ForTest method
(panicking in non-test contexts) that returns that unexported type.

This is unusual style (exported returning unexported) but declutters
godoc and makes call sites both more explicit and easier to read
without the "ForTest" suffix polluting the symbols. Now FooForTest()
changes into ForTest().Foo().

This was motivated by a pending change moving a bunch of code out of
LocalBackend into other packages that required adding more ForTest
methods to LocalBackend to keep the tests (now in other packages)
working. Instead, do this refactor now so the future change is prettier.

Updates #12614
Updates #cleanup

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: Ib25e6d76d48dc8622ac3a955e0b1220d582e63a8
2026-06-27 16:11:42 -07:00
1c0e833749 ipn/ipnlocal: normalize IPv6-mapped IPv4 addrs in WhoIs
WhoIs lookups for an IPv6-mapped IPv4 address such as
"::ffff:100.87.98.86" failed to match the node's canonical IPv4
address. Unmap the address before looking it up so these resolve.

Fixes #20235

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Bouke van der Bijl <i@bou.ke>
2026-06-27 11:36:30 -07:00
Raj SinghandGitHub b64209b248 ipn/config: add RelayServerPort and RelayServerStaticEndpoints to config file (#18300) 2026-06-26 15:45:29 -05:00
Brad FitzpatrickandBrad Fitzpatrick d4f2917c1b wgengine, ipn/ipnlocal: route PeerForIP through LocalBackend's live data
userspaceEngine.PeerForIP read from e.netMap.Peers and
e.lastCfgFull.Peers, both of which go stale when peers arrive via
netmap deltas (which skip Engine.SetNetworkMap and Engine.Reconfig).
Every PeerForIP caller (Engine.Ping, the TSMP disco-key handler,
pendopen diagnostics, tsdial.Dialer.UseNetstackForIP, and
LocalBackend.GetPeerEndpointChanges) would report "no matching peer"
for freshly-added peers.

Fix it the same way SetPeerByIPPacketFunc fixed the outbound packet
hot path: have LocalBackend install a callback that reads the live
nodeBackend. nb.NodeByAddr is built from both SelfNode and Peers
(updateNodeByAddrLocked), so a single lookup covers the common case
with IsSelf set when the matched node ID is SelfNode's. The subnet-
route / exit-node-default-route slow path goes through a new
Engine.PeerKeyForIP that exposes the engine's AllowedIPs BART table
(the same table the outbound packet hot path already consults, with
exit-node selection honored), and resolves the matched key back to a
NodeView via the live nodeBackend.

Updates #12542

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I0d4b0d8997c8e796b7367c46b49b61d4fdc717b0
2026-06-23 14:37:15 -07:00
Anton TolchanovandAnton Tolchanov f442cda999 ipn/ipnlocal: consider all DERP regions for exit node recommendations
When recommending an exit node, suggestExitNodeLocked ranks candidates by
the latency to their home DERP region, taken from the most recent netcheck
report. But netcheck alternates between full reports, which probe every
region, and incremental reports, which only re-probe the home region and a
handful of the fastest regions. When the most recent report is incremental,
the suggestion fell back to a random for exit nodes that are far away.

Now we rank candidates against the best recent latency, tracked by the
`netcheck.Client` - the same data that is used to pick the preferred
DERP. It uses a history of measurements which includes a full netcheck
report, so should cover all DERP regions.

Updates tailscale/corp#17516

Signed-off-by: Anton Tolchanov <anton@tailscale.com>
2026-06-22 12:28:09 +02:00
Alex ChanandAlex Chan c3c2aa7093 all: don't repeat the the word "the" unnecessarily
Updates #cleanup

Change-Id: Ic1f430cd5dbf6cc1a385c59074a5d5cabe6fca57
Signed-off-by: Alex Chan <alexc@tailscale.com>
2026-06-18 16:32:08 +01:00
Brad FitzpatrickandBrad Fitzpatrick 6596d237a3 ipn/ipnlocal: add wireguard session state metrics + publish on IPN bus
Updates #19989
Updates tailscale/corp#42874

Change-Id: I843ed95bc7b0f5cd38ba1467332c6b022901e254
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-06-15 11:41:18 -07:00
Brad FitzpatrickandBrad Fitzpatrick 1deb6a8449 ipn: add no-disconnect in-process bus subscribers
Add NotifyInProcessNoDisconnect for in-process IPN bus subscribers that
must apply every bus update. When such a subscriber falls behind, block
Notify production instead of sending the terminal fell-behind message and
closing the watch.

This is intentionally not available over LocalAPI, where a slow or stuck
out-of-process client should still be disconnected rather than allowed to
stall tailscaled. In-process callers that use the bit must keep their
callbacks fast and must not call back into LocalBackend from the callback.

Updates #20062

Change-Id: I730ad61a07475243bb226fba2262c1a3ded211ae
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-06-09 12:51:38 -07:00
Brad FitzpatrickandBrad Fitzpatrick edcc2c94d9 ipn: enforce lossless IPN bus delta streams
New-style IPN bus subscribers consume stateful delta streams. Reject
NotifyRateLimit when it is combined with those subscription bits so
tailscaled cannot merge or delay messages that clients need to apply in
order.

Also stop silently dropping notifications when a watcher falls behind.
Remove the watcher, replace its stale queue with one terminal ErrMessage
notification, and close the watch.

Updates #20062

Change-Id: Id9d402ea76f4011cd23f122adf62f30dd4b6f90b
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-06-09 11:12:20 -07:00
Brad FitzpatrickandBrad Fitzpatrick 2ba426802f ipn/ipnlocal: fix 'tailscale status --peers=false' missing user profile
Fixes #19894

Change-Id: I310504987170e0742480c8a02706eb0dbf4ec3dc
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-05-31 20:34:43 -07:00
kari-tsandGitHub 7355116c05 ipn/store: make WriteState(id, nil) delete key instead of adding nil entry (#19920)
All StateStore implementations store a nil value in the cache map when WriteState is called with a nil byte slice instead of deleting the key. This causes ReadState to return (nil, nil) instead of (nil, ErrStateNotExist), since the key is still present in the map.

This breaks reset-auth in Windows, Linux, and Android, and the node can't log back in without manually editing the state file. (macOS uses a different state store)
DeleteProfile, DeleteAllProfilesForUser, setUnattendedModeAsConfigured are impacted but don't seem to break because the deleted keys are not reread.

This deletes the key from the cache instead.

Fixes tailscale/corp#42477

Signed-off-by: kari-ts <kari@tailscale.com>
2026-05-29 11:22:14 -07:00
Brad FitzpatrickandBrad Fitzpatrick c9fb05b6f5 ipn/ipnlocal: don't dup-suppress UserProfiles on IPNBus on profile switches
Fixes #19889

Change-Id: I324a735c13772c0c79ed7392c0baa5064b34823b
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-05-27 14:47:02 -07:00
Brad FitzpatrickandBrad Fitzpatrick a8f40a2ca5 ipn/ipnlocal: add missing bus notify of peers on full netmap
The prior aa5da2e5f2 ("process node adds/removes in constant
time") commit missed a bus notification case, where new-style
subscribers set NotifyNoNetmap and then the controlclient map routing
sends a full update (rather than a delta). Those profiles + peers
need to be put on the bus too.

I noticed this only when porting the Android app over to use the
new bus stuff.

Updates #19607
Updates #12542

Change-Id: I82c35011d2c532222ca27f7d4e790522c31bd156
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-05-27 08:03:47 -07:00
Simon LawandGitHub 7dabebc691 net/traffic: switch rendezvous hashing from SHA256 to FNV-1a (#19821)
In PR tailscale/corp#30448, we originally decided to break ties using
SHA256 for our rendezvous hashing algorithm. Now that we’ve had some
experience with it, we think that FNV-1a is a better choice. It
distributes bits evenly, it’s much faster, and it doesn’t need to be
cryptographically secure. The FNV designers recommend FNV-1a over the
deprecated FNV-1.

This PR makes the switch and updates the related tests, since changing
the algorithm changes which stable pick gets selected. As of 2026-05,
this is the best time to make this change, since there are almost no
clients in the wild with traffic steering enabled.

Updates #17366
Updates tailscale/corp#29964
Updates tailscale/corp#29966
Updates tailscale/corp#33033

Signed-off-by: Simon Law <sfllaw@tailscale.com>
2026-05-21 10:11:59 -07:00
Brad FitzpatrickandBrad Fitzpatrick aa5da2e5f2 ipn/ipnlocal, control/controlclient: process node adds/removes in constant time
For large tailnets (~50k+ nodes) with frequent peer churn (ephemeral
GitHub Actions workers etc.), tailscaled used to rebuild the full
netmap and fan it out on the IPN bus on every MapResponse that
added or removed a peer. There were two O(N) costs per delta: the
full netmap rebuild + every Notify.NetMap encode to every bus watcher.

This change tackles both:

  1. Plumb O(1) peer add/remove through the delta path. PeersChanged
     and PeersRemoved no longer prevent the delta happy path; instead,
     they mutate the per-node-backend peer map in place.

  2. Restrict ipn.Notify.NetMap emission to the platforms whose host
     GUIs still depend on it (Windows, macOS, iOS) and migrate
     in-tree consumers off it everywhere else:

     - Migrate reactive consumers (containerboot, kube agents,
       sniproxy, tsconsensus, etc.) off Notify.NetMap to the
       previously-added Notify.SelfChange signal so they no longer
       have to subscribe to the full netmap.
     - Add ipn.NotifyNoNetMap so GUI clients on "legacy-emit" platforms
       that have already migrated can opt out of the per-watcher
       NetMap encode.
     - Gate Notify.NetMap emission on the producer side by a compile-
       time GOOS check, so the supporting code is dead-code-eliminated
       on Linux and other geese where no GUI consumer needs it.

Re-running BenchmarkGiantTailnet from tstest/largetailnet, which was
added along with baseline numbers on unmodified main in ad5436af0d,
the per-delta cost (one peer add+remove pair) is now ~O(1) regardless
of tailnet size N:

    N         no-watcher (ms/op)            bus-watcher (ms/op)
              before    now     factor      before    now     factor
     10000        32   0.11       300x         166   0.13      1300x
     50000       222   0.11      2000x         865   0.13      6700x
    100000       504   0.12      4100x        1765   0.13     13400x
    250000      1551   0.12     12500x        4696   0.15     32400x

Updates #12542

Change-Id: I94e34b37331d1a8ec74c299deffadf4d061fda9e
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-05-21 09:26:19 -07:00
Simon LawandGitHub 93dbd33ef7 ipn/ipnlocal: stub system interfaces for TestShouldUseOneCGNATRoute (#19807)
The TestShouldUseOneCGNATRoute test fails when the underlying system
interfaces don’t match what the underlying assumptions of the test.
That assumption was that there would only ever be one CGNAT interface:
the Tailscale one.

This breaks on Linux when border0 is installed because border0 also
creates an interface with a CGNAT route.

This patch stubs netmon.RegisterInterfaceGetter to replace the system
interfaces and netmon.SetTailscaleInterfaceProps to identify the test
data that defines the Tailscale interface.

This patch also tests the control knob override for CGNAT for every
combination of operating system and system interfaces, instead of just
a couple of combinations.

Fixes #19731

Signed-off-by: Simon Law <sfllaw@tailscale.com>
2026-05-20 16:00:14 -07:00
kari-tsandGitHub c721189cef ipn/ipnlocal: prefer one CGNAT route on Android (#19652)
Android rebuilds its VpnService interface when the VPN route
configuration changes, which tears down long lived TCP connections
through the tunnel. Use the same automatic OneCGNATRoute behavior as
macOS on Android, and prefer the single CGNAT route when no other
interface is using the CGNAT, falling back to fine grained peer routes
otherwise.

Updates tailscale/tailscale#19591

Signed-off-by: kari <kari@tailscale.com>
2026-05-05 19:11:17 -07:00
Scott GrahamandNick Khyl cb5a53c424 ipn/ipnlocal: preserve b.loginFlags in auto-login cc.Login calls
LocalBackend stores loginFlags at construction so that per-instance
properties (e.g. LoginEphemeral set by tsnet.Server.Ephemeral) persist
for the session. StartLoginInteractiveAs already merges b.loginFlags
into its cc.Login call, but the two auto-login call sites pass bare
controlclient.LoginDefault, silently dropping any stored flags.

Merge b.loginFlags at both auto-login call sites to match the existing
StartLoginInteractiveAs pattern. LoginDefault is zero so this is a
no-op when loginFlags is empty, and restores the documented behavior
when it isn't.

Fixes #15852

Signed-off-by: Scott Graham <scott.github@h4ck3r.net>
2026-04-17 23:31:18 -05:00
Brad FitzpatrickandBrad Fitzpatrick 5a899e406d ipn/ipnlocal: add health.Tracker to tests where it was warning in CI
To denoise log output, to make it easier to find real failures.

Updates #19252

Change-Id: Iae64a9278c70de24a236c39e3d181a509a512a0b
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-04-05 20:20:07 -07:00
Brad FitzpatrickandBrad Fitzpatrick 5ef3713c9f cmd/vet: add subtestnames analyzer; fix all existing violations
Add a new vet analyzer that checks t.Run subtest names don't contain
characters requiring quoting when re-running via "go test -run". This
enforces the style guide rule: don't use spaces or punctuation in
subtest names.

The analyzer flags:
- Direct t.Run calls with string literal names containing spaces,
  regex metacharacters, quotes, or other problematic characters
- Table-driven t.Run(tt.name, ...) calls where tt ranges over a
  slice/map literal with bad name field values

Also fix all 978 existing violations across 81 test files, replacing
spaces with hyphens and shortening long sentence-like names to concise
hyphenated forms.

Updates #19242

Change-Id: Ib0ad96a111bd8e764582d1d4902fe2599454ab65
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-04-05 15:52:51 -07:00
M. J. FrombergerandGitHub 211ef67222 tailcfg,ipn/ipnlocal: regulate netmap caching via a node attribute (#19117)
Add a new tailcfg.NodeCapability (NodeAttrCacheNetworkMaps) to control whether
a node with support for caching network maps will attempt to do so. Update the
capability version to reflect this change (mainly as a safety measure, as the
control plane does not currently need to know about it).

Use the presence (or absence) of the node attribute to decide whether to create
and update a netmap cache for each profile. If caching is disabled, discard the
cached data; this allows us to use the presence of a cached netmap as an
indicator it should be used (unless explicitly overridden). Add a test that
verifies the attribute is respected. Reverse the sense of the environment knob
to be true by default, with an override to disable caching at the client
regardless what the node attribute says.

Move the creation/update of the netmap cache (when enabled) until after
successfully applying the network map, to reduce the possibility that we will
cache (and thus reuse after a restart) a network map that fails to correctly
configure the client.

Updates #12639

Change-Id: I1df4dd791fdb485c6472a9f741037db6ed20c47e
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2026-04-01 15:02:53 -07:00
KevinLiang10andGitHub 45f989f52a ipn/ipnlocal: warn incompatibility between no-snat-routes and exitnode (#19023)
* ipn/ipnlocal: warn incompatibility between no-snat-routes and exitnode

This commit adds a warning to health check when the --snat-subnet-routes=false flag for subnet router is
set alone side --advertise-exit-node=true. These two would conflict with each other and result internet-bound
traffic from peers using this exit node no masqueraded to the node's source IP and fail to route return
packets back. The described combination is not valid until we figure out a way to separate exitnode masquerade rule and skip it for subnet routes.

Updates #18725

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>

* use date instead of for now to clarify effectivness

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>

---------

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>
2026-03-26 12:36:31 -04:00
kari-tsandGitHub 9992b7c817 ipn,ipn/local: broadcast ClientVersion if AutoUpdate.Check (#19107)
If AutoUpdate.Check is false, the client has opted out of checking for updates, so we shouldn't broadcast ClientVersion. If the client has opted in, it should be included in the initial Notify.

Updates tailscale/corp#32629

Signed-off-by: kari-ts <kari@tailscale.com>
2026-03-24 15:06:20 -07:00
Amal BansodeandGitHub 04ef9d80b5 ipn/ipnlocal: add a map for node public key to node ID lookups (#19051)
This path is currently only used by DERP servers that have also
enabled `verify-clients` to ensure that only authorized clients
within a Tailnet are allowed to use said DERP server.

The previous naive linear scan in NodeByKey would almost
certainly lead to bad outcomes with a large enough netmap, so
address an existing todo by building a map of node key -> node ID.

Updates #19042

Signed-off-by: Amal Bansode <amal@tailscale.com>
2026-03-23 10:23:28 -07:00
Brendan CreaneandGitHub ffa7df2789 ipn: reject advertised routes with non-address bits set (#18649)
* ipn: reject advertised routes with non-address bits set

The config file path, EditPrefs local API, and App Connector API were
accepting invalid subnet route prefixes with non-address bits set (e.g.,
2a01:4f9:c010:c015::1/64 instead of 2a01:4f9:c010:c015::/64). All three
paths now reject prefixes where prefix != prefix.Masked() with an error
message indicating the expected masked form.

Updates tailscale/corp#36738

Signed-off-by: Brendan Creane <bcreane@gmail.com>

* address review comments

Signed-off-by: Brendan Creane <bcreane@gmail.com>

---------

Signed-off-by: Brendan Creane <bcreane@gmail.com>
2026-03-20 10:10:43 -07:00
Gesa StupperichandGitHub ca9aa20255 ipn/ipnlocal: populate Groups field in profileFromView
This populates UserProfile.Groups in the WhoIs response from the
local backend with the groups of the corresponding user in the
netmap.

This allows tsnet apps to see (and e.g. forward) which groups a
user making a request belongs to - as long as the tsnet app runs
on a node that been granted the tailscale.com/visible-groups
capability via node attributes. If that's not the case or the
user doesn't belong to any groups allow-listed via the node
attribute, Groups won't be populated.

Updates tailscale/corp#31529

Signed-off-by: Gesa Stupperich <gesa@tailscale.com>
2026-03-19 21:46:55 +00:00
Brad FitzpatrickandBrad Fitzpatrick 2a64c03c95 types/ptr: deprecate ptr.To, use Go 1.26 new
Updates #18682

Change-Id: I62f6aa0de2a15ef8c1435032c6aa74a181c25f8f
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-03-05 20:13:18 -08:00
f4aea70f7a ipn/ipnlocal: add basic support for netmap caching (#18530)
This commit is based on ff0978ab, and extends #18497 to connect network map
caching to the LocalBackend. As implemented, only "whole" netmap values are
stored, and we do not yet handle incremental updates. As-written, the feature must
be explicitly enabled via the TS_USE_CACHED_NETMAP envknob, and must be
considered experimental.

Updates #12639

Co-Authored-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I48a1e92facfbf7fb3a8e67cff7f2c9ab4ed62c83
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2026-02-17 14:51:54 -08:00
KevinLiang10andGitHub 03461ea7fb wgengine/netstack: add local tailscale service IPs to route and terminate locally (#18461)
* wgengine/netstack: add local tailscale service IPs to route and terminate locally

This commit adds the tailscales service IPs served locally to OS routes, and
make interception to packets so that the traffic terminates locally without
making affects to the HA traffics.

Fixes tailscale/corp#34048

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>

* fix test

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>

* add ready field to avoid accessing lb before netstack starts

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>

* wgengine/netstack: store values from lb to avoid acquiring a lock

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>

* add active services to netstack on starts with stored prefs.

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>

* fix comments

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>

* update comments

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>

---------

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>
2026-01-30 16:46:03 -05:00
Will NorrisandWill Norris 3ec5be3f51 all: remove AUTHORS file and references to it
This file was never truly necessary and has never actually been used in
the history of Tailscale's open source releases.

A Brief History of AUTHORS files
---

The AUTHORS file was a pattern developed at Google, originally for
Chromium, then adopted by Go and a bunch of other projects. The problem
was that Chromium originally had a copyright line only recognizing
Google as the copyright holder. Because Google (and most open source
projects) do not require copyright assignemnt for contributions, each
contributor maintains their copyright. Some large corporate contributors
then tried to add their own name to the copyright line in the LICENSE
file or in file headers. This quickly becomes unwieldy, and puts a
tremendous burden on anyone building on top of Chromium, since the
license requires that they keep all copyright lines intact.

The compromise was to create an AUTHORS file that would list all of the
copyright holders. The LICENSE file and source file headers would then
include that list by reference, listing the copyright holder as "The
Chromium Authors".

This also become cumbersome to simply keep the file up to date with a
high rate of new contributors. Plus it's not always obvious who the
copyright holder is. Sometimes it is the individual making the
contribution, but many times it may be their employer. There is no way
for the proejct maintainer to know.

Eventually, Google changed their policy to no longer recommend trying to
keep the AUTHORS file up to date proactively, and instead to only add to
it when requested: https://opensource.google/docs/releasing/authors.
They are also clear that:

> Adding contributors to the AUTHORS file is entirely within the
> project's discretion and has no implications for copyright ownership.

It was primarily added to appease a small number of large contributors
that insisted that they be recognized as copyright holders (which was
entirely their right to do). But it's not truly necessary, and not even
the most accurate way of identifying contributors and/or copyright
holders.

In practice, we've never added anyone to our AUTHORS file. It only lists
Tailscale, so it's not really serving any purpose. It also causes
confusion because Tailscalars put the "Tailscale Inc & AUTHORS" header
in other open source repos which don't actually have an AUTHORS file, so
it's ambiguous what that means.

Instead, we just acknowledge that the contributors to Tailscale (whoever
they are) are copyright holders for their individual contributions. We
also have the benefit of using the DCO (developercertificate.org) which
provides some additional certification of their right to make the
contribution.

The source file changes were purely mechanical with:

    git ls-files | xargs sed -i -e 's/\(Tailscale Inc &\) AUTHORS/\1 contributors/g'

Updates #cleanup

Change-Id: Ia101a4a3005adb9118051b3416f5a64a4a45987d
Signed-off-by: Will Norris <will@tailscale.com>
2026-01-23 15:49:45 -08:00
M. J. FrombergerandGitHub ce12863ee5 ipn/ipnlocal: manage per-profile subdirectories in TailscaleVarRoot (#18485)
In order to better manage per-profile data resources on the client, add methods
to the LocalBackend to support creation of per-profile directory structures in
local storage. These methods build on the existing TailscaleVarRoot config, and
have the same limitation (i.e., if no local storage is available, it will
report an error when used).

The immediate motivation is to support netmap caching, but we can also use this
mechanism for other per-profile resources including pending taildrop files and
Tailnet Lock authority caches.

This commit only adds the directory-management plumbing; later commits will
handle migrating taildrop, TKA, etc. to this mechanism, as well as caching
network maps.

Updates #12639

Change-Id: Ia75741955c7bf885e49c1ad99f856f669a754169
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2026-01-23 10:09:46 -08:00
c3b7f24051 ipn,ipn/local: always accept routes for Tailscale Services (cgnat range) (#18173)
Updates #18198

Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
Co-authored-by: James Tucker <raggi@tailscale.com>
2026-01-14 18:20:00 +00:00
Alex ChanandAlex Chan b38dd1ae06 ipn/ipnlocal: don't panic if there are no suitable exit nodes
In suggestExitNodeLocked, if no exit node candidates have a home DERP or
valid location info, `bestCandidates` is an empty slice. This slice is
passed to `selectNode` (`randomNode` in prod):

```go func randomNode(nodes views.Slice[tailcfg.NodeView], …) tailcfg.NodeView {
	…
	return nodes.At(rand.IntN(nodes.Len()))
}
```

An empty slice becomes a call to `rand.IntN(0)`, which panics.

This patch changes the behaviour, so if we've filtered out all the
candidates before calling `selectNode`, reset the list and then pick
from any of the available candidates.

This patch also updates our tests to give us more coverage of `randomNode`,
so we can spot other potential issues.

Updates #17661

Change-Id: I63eb5e4494d45a1df5b1f4b1b5c6d5576322aa72
Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-11-25 19:05:13 +00:00
Simon LawandGitHub 848978e664 ipn/ipnlocal: test traffic-steering when feature is not enabled (#17997)
In PR tailscale/corp#34401, the `traffic-steering` feature flag does
not automatically enable traffic steering for all nodes. Instead, an
admin must add the `traffic-steering` node attribute to each client
node that they want opted-in.

For backwards compatibility with older clients, tailscale/corp#34401
strips out the `traffic-steering` node attribute if the feature flag
is not enabled, even if it is set in the policy file. This lets us
safely disable the feature flag.

This PR adds a missing test case for suggested exit nodes that have no
priority.

Updates tailscale/corp#34399

Signed-off-by: Simon Law <sfllaw@tailscale.com>
2025-11-25 09:21:55 -08:00
Simon LawandGitHub 9c3a2aa797 ipn/ipnlocal: replace log.Printf with logf (#18045)
Updates #cleanup

Signed-off-by: Simon Law <sfllaw@tailscale.com>
2025-11-24 17:42:58 -08:00
Brad FitzpatrickandBrad Fitzpatrick bd29b189fe types/netmap,*: remove some redundant fields from NetMap
Updates #12639

Change-Id: Ia50b15529bd1c002cdd2c937cdfbe69c06fa2dc8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-11-18 07:56:10 -08:00
Brad FitzpatrickandBrad Fitzpatrick 653d0738f9 types/netmap: remove PrivateKey from NetworkMap
It's an unnecessary nuisance having it. We go out of our way to redact
it in so many places when we don't even need it there anyway.

Updates #12639

Change-Id: I5fc72e19e9cf36caeb42cf80ba430873f67167c3
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-11-16 15:32:51 -08:00
146ea42822 ipn/ipnlocal: remove all the weird locking (LockedOnEntry, UnlockEarly, etc)
Fixes #11649
Updates #16369

Co-authored-by: James Sanderson <jsanderson@tailscale.com>
Change-Id: I63eaa18fe870ddf81d84b949efac4d1b44c3db86
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-11-13 19:20:07 -08:00
Brad FitzpatrickandBrad Fitzpatrick 8ed6bb3198 ipn/ipnlocal: move vipServiceHash etc to serve.go, out of local.go
Updates #12614

Change-Id: I3c16b94fcb997088ff18d5a21355e0279845ed7e
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-11-10 15:35:45 -08:00
Patrick O'DohertyandGitHub e45557afc0 types/persist: add AttestationKey (#17281)
Extend Persist with AttestationKey to record a hardware-backed
attestation key for the node's identity.

Add a flag to tailscaled to allow users to control the use of
hardware-backed keys to bind node identity to individual machines.

Updates tailscale/corp#31269


Change-Id: Idcf40d730a448d85f07f1bebf387f086d4c58be3

Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
2025-10-10 10:28:36 -07:00
Alex ChanandAlex Chan a9334576ea ipn/ipnlocal: use named arguments for mockControl.send()
Updates #cleanup

Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-10-07 14:50:30 +01:00
M. J. FrombergerandGitHub e0f222b686 appc,ipn/ipnlocal: receive AppConnector updates via the event bus (#17411)
Add subscribers for AppConnector events

Make the RouteAdvertiser interface optional We cannot yet remove it because
the tests still depend on it to verify correctness. We will need to separately
update the test fixtures to remove that dependency.

Publish RouteInfo via the event bus, so we do not need a callback to do that. 
Replace it with a flag that indicates whether to treat the route info the connector 
has as "definitive" for filtering purposes.

Update the tests to simplify the construction of AppConnector values now that a
store callback is no longer required. Also fix a couple of pre-existing racy tests that 
were hidden by not being concurrent in the same way production is.

Updates #15160
Updates #17192

Change-Id: Id39525c0f02184e88feaf0d8a3c05504850e47ee
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-06 15:04:17 -07:00
7407f404d9 ipn/ipnlocal: fix setAuthURL / setWgengineStatus race condition (#17408)
If we received a wg engine status while processing an auth URL, there was a
race condition where the authURL could be reset to "" immediately after we
set it.

To fix this we need to check that we are moving from a non-Running state to
a Running state rather than always resetting the URL when we "move" into a
Running state even if that is the current state.

We also need to make sure that we do not return from stopEngineAndWait until
the engine is stopped: before, we would return as soon as we received any
engine status update, but that might have been an update already in-flight
before we asked the engine to stop. Now we wait until we see an update that
is indicative of a stopped engine, or we see that the engine is unblocked
again, which indicates that the engine stopped and then started again while
we were waiting before we checked the state.

Updates #17388

Signed-off-by: James Sanderson <jsanderson@tailscale.com>
Co-authored-by: Nick Khyl <nickk@tailscale.com>
2025-10-06 22:48:43 +01:00
M. J. FrombergerandGitHub 127a967207 appc,*: publish events for route updates and storage (#17392)
Add and wire up event publishers for these two event types in the AppConnector.
Nothing currently subscribes to them, so this is harmless. Subscribers for
these events will be added in a near-future commit.

As part of this, move the appc.RouteInfo type to the types/appctype package.
It does not contain any package-specific details from appc. Beside it, add
appctype.RouteUpdate to carry route update event state, likewise not specific
to appc.  Update all usage of the appc.* types throughout to use appctype.*
instead, and update depaware files to reflect these changes.

Add a Close method to the AppConnector to make sure the client gets cleaned up
when the connector is dropped (we re-create connectors).

Update the unit tests in the appc package to also check the events published
alongside calls to the RouteAdvertiser.

For now the tests still rely on the RouteAdvertiser for correctness; this is OK
for now as the two methods are always performed together.  In the near future,
we need to rework the tests so not require that, but that will require building
some more test fixtures that we can handle separately.

Updates #15160
Updates #17192

Change-Id: I184670ba2fb920e0d2cb2be7c6816259bca77afe
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-02 09:31:42 -07:00
M. J. FrombergerandGitHub 67f1081269 appc,ipn/ipnlocal: add a required event bus to the AppConnector type (#17390)
Require the presence of the bus, but do not use it yet.  Check for required
fields and update tests and production use to plumb the necessary arguments.

Updates #15160
Updates #17192

Change-Id: I8cefd2fdb314ca9945317d3320bd5ea6a92e8dcb
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-01 12:00:32 -07:00