summaryrefslogtreecommitdiffhomepage
AgeCommit message (Collapse)AuthorFilesLines
2025-10-14cmd/{containerboot,k8s-proxy}: disconnect from control before shutdowndavidb/containerboot-disconnect-controlDavid Bond5-62/+79
This commit modifies containerboot to call the local api endpoint to disconnect from the control plane upon shutdown. This functionality is enabled using a new environment variable: `EXPERIMENTAL_DISCONNECT_ON_SHUTDOWN` When using an instance as a HA app connector or subnet router this environment variable should be set to give connected clients enough time to update their netmap and fail over to the next active instance. This commit also includes some minor spelling/grammar fixes. Updates #14020 Signed-off-by: David Bond <davidsbond93@gmail.com>
2025-10-10util/eventbus/eventbustest: add support for synctest instead of timers (#17522)Claus Lensbøl6-144/+229
Before synctest, timers was needed to allow the events to flow into the test bus. There is still a timer, but this one is not derived from the test deadline and it is mostly arbitrary as synctest will render it practically non-existent. With this approach, tests that do not need to test for the absence of events do not rely on synctest. Updates #15160 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
2025-10-10ipn/ipnlocal: strip AttestationKey in redacted prefs view (#17527)Patrick O'Doherty1-0/+1
Updates tailscale/corp#31269 Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
2025-10-10clientupdate, util/osshare, util/winutil, version: improve Windows GUI ↵Aaron Klotz7-33/+146
filename resolution and WinUI build awareness On Windows arm64 we are going to need to ship two different GUI builds; one for Win10 (GOARCH=386) and one for Win11 (GOARCH=amd64, tags += winui). Due to quirks in MSI packaging, they cannot both share the same filename. This requires some fixes in places where we have hardcoded "tailscale-ipn" as the GUI filename. We also do some cleanup in clientupdate to ensure that autoupdates will continue to work correctly with the temporary "-winui" package variant. Fixes #17480 Updates https://github.com/tailscale/corp/issues/29940 Signed-off-by: Aaron Klotz <aaron@tailscale.com>
2025-10-10types/persist: add AttestationKey (#17281)Patrick O'Doherty26-42/+370
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-10all: specify explicit JSON format for time.Duration (#17307)Joe Tsai2-2/+2
The default representation of time.Duration has different JSON representation between v1 and v2. Apply an explicit format flag that uses the v1 representation so that this behavior does not change if serialized with v2. Updates tailscale/corp#791 Signed-off-by: Joe Tsai <joetsai@digital-static.net>
2025-10-10net/netmon: handle net.IPAddr types during interface address parsing (#17523)Jonathan Nobels2-0/+48
updates tailscale/tailscale#16836 Android's altNetInterfaces implementation now returns net.IPAddr types which netmon wasn't handling. Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
2025-10-10wgengine/magicsock: add clientmetrics for TX bytes/packets by af & conn type ↵Jordan Whited2-0/+34
(#17515) Updates tailscale/corp#33206 Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-10-10util/eventbus: run subscriber functions in a goroutine (#17510)M. J. Fromberger1-14/+24
With a channel subscriber, the subscription processing always occurs on another goroutine. The SubscriberFunc (prior to this commit) runs its callbacks on the client's own goroutine. This changes the semantics, though: In addition to more directly pushing back on the publisher, a publisher and subscriber can deadlock in a SubscriberFunc but succeed on a Subscriber. They should behave equivalently regardless which interface they use. Arguably the caller should deal with this by creating its own goroutine if it needs to. However, that loses much of the benefit of the SubscriberFunc API, as it will need to manage the lifecycle of that goroutine. So, for practical ergonomics, let's make the SubscriberFunc do this management on the user's behalf. (We discussed doing this in #17432, but decided not to do it yet). We can optimize this approach further, if we need to, without changing the API. Updates #17487 Change-Id: I19ea9e8f246f7b406711f5a16518ef7ff21a1ac9 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-10cmd/tailscale/cli,ipn/conffile: add declarative config mode for Services ↵Naman Sood6-13/+556
(#17435) This commit adds the subcommands `get-config` and `set-config` to Serve, which can be used to read the current Tailscale Services configuration in a standard syntax and provide a configuration to declaratively apply with that same syntax. Both commands must be provided with either `--service=svc:service` for one service, or `--all` for all services. When writing a config, `--set-config --all` will overwrite all existing Services configuration, and `--set-config --service=svc:service` will overwrite all configuration for that particular Service. Incremental changes are not supported. Fixes tailscale/corp#30983. cmd/tailscale/cli: hide serve "get-config"/"set-config" commands for now tailscale/corp#33152 tracks unhiding them when docs exist. Signed-off-by: Naman Sood <mail@nsood.in>
2025-10-10sessionrecording: add destination to struct for tsrecorder (#17520)Tom Meadows1-0/+14
when tsrecorder receives events, it populates this field with information about the node the request was sent to. Updates #17141 Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
2025-10-10tsweb/varz: add support for ShardedInt metricsAnton Tolchanov3-1/+20
Fixes tailscale/corp#33236 Signed-off-by: Anton Tolchanov <anton@tailscale.com>
2025-10-09wgengine/magicsock: do not apply node view updates to a closed Conn (#17517)M. J. Fromberger1-0/+5
Fixes #17516 Change-Id: Iae2dab42d6f7bc618478d360a1005537c1fa1bbd Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-09wgengine/magicsock: fix docs for send clientmetrics (#17514)Jordan Whited1-3/+10
Updates #cleanup Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-10-09wgengine/magicsock: add clientmetrics for RX bytes by af & conn type (#17512)Jordan Whited2-0/+19
Updates tailscale/corp#33206 Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-10-09wgengine/magicsock: remove unused arg in deregisterMetrics (#17513)Jordan Whited1-2/+2
Updates #cleanup Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-10-09feature/relayserver: init server at config time instead of request time (#17484)Jordan Whited4-13/+12
The lazy init led to confusion and a belief that was something was wrong. It's reasonable to expect the daemon to listen on the port at the time it's configured. Updates tailscale/corp#33094 Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-10-08feature/featuretags: make bird depend on advertiseroutesBrad Fitzpatrick2-2/+6
Updates #cleanup Change-Id: I87082919064a5652c0d976cadd6d159787bb224a Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-08net/dns, wgengine: use viewer/cloner for ConfigBrad Fitzpatrick5-91/+222
Per earlier TODO. Updates #17506 Change-Id: I21fe851c4bcced98fcee844cb428ca9c2f6b0588 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-08net/dns, ipn/ipnlocal: fix regressions from change moving away from deephashBrad Fitzpatrick4-7/+94
I got sidetracked apparently and never finished writing this Clone code in 316afe7d02babc (#17448). (It really should use views instead.) And then I missed one of the users of "routerChanged" that was broken up into "routerChanged" vs "dnsChanged". This broke integration tests elsewhere. Fixes #17506 Change-Id: I533bf0fcf3da9ac6eb4a6cdef03b8df2c1fb4c8e Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-08flake.nix: update Nix to use tailscale/go 1.25.2 (#17500)Mike O'Driscoll5-4/+18
Update Nix flake to use go 1.25.2 Create the hash from the toolchain rev file automatically from update-flake.sh Updates tailscale/go#135 Signed-off-by: Mike O'Driscoll <mikeo@tailscale.com>
2025-10-08cmd/tailscale/cli: only print authURLs and device approval URLs onceAlex Chan3-13/+226
This patch fixes several issues related to printing login and device approval URLs, especially when `tailscale up` is interrupted: 1. Only print a login URL that will cause `tailscale up` to complete. Don't print expired URLs or URLs from previous login attempts. 2. Print the device approval URL if you run `tailscale up` after previously completing a login, but before approving the device. 3. Use the correct control URL for device approval if you run a bare `tailscale up` after previously completing a login, but before approving the device. 4. Don't print the device approval URL more than once (or at least, not consecutively). Updates tailscale/corp#31476 Updates #17361 ## How these fixes work This patch went through a lot of trial and error, and there may still be bugs! These notes capture the different scenarios and considerations as we wrote it, which are also captured by integration tests. 1. We were getting stale login URLs from the initial IPN state notification. When the IPN watcher was moved to before Start() in c011369, we mistakenly continued to request the initial state. This is only necessary if you start watching after you call Start(), because you may have missed some notifications. By getting the initial state before calling Start(), we'd get a stale login URL. If you clicked that URL, you could complete the login in the control server (if it wasn't expired), but your instance of `tailscale up` would hang, because it's listening for login updates from a different login URL. In this patch, we no longer request the initial state, and so we don't print a stale URL. 2. Once you skip the initial state from IPN, the following sequence: * Run `tailscale up` * Log into a tailnet with device approval * ^C after the device approval URL is printed, but without approving * Run `tailscale up` again means that nothing would ever be printed. `tailscale up` would send tailscaled the pref `WantRunning: true`, but that was already the case so nothing changes. You never get any IPN notifications, and in particular you never get a state change to `NeedsMachineAuth`. This means we'd never print the device approval URL. In this patch, we add a hard-coded rule that if you're doing a simple up (which won't trigger any other IPN notifications) and you start in the `NeedsMachineAuth` state, we print the device approval message without waiting for an IPN notification. 3. Consider the following sequence: * Run `tailscale up --login-server=<custom server>` * Log into a tailnet with device approval * ^C after the device approval URL is printed, but without approving * Run `tailscale up` again We'd print the device approval URL for the default control server, rather than the real control server, because we were using the `prefs` from the CLI arguments (which are all the defaults) rather than the `curPrefs` (which contain the custom login server). In this patch, we use the `prefs` if the user has specified any settings (and other code will ensure this is a complete set of settings) or `curPrefs` if it's a simple `tailscale up`. 4. Consider the following sequence: you've logged in, but not completed device approval, and you run `down` and `up` in quick succession. * `up`: sees state=NeedsMachineAuth * `up`: sends `{wantRunning: true}`, prints out the device approval URL * `down`: changes state to Stopped * `up`: changes state to Starting * tailscaled: changes state to NeedsMachineAuth * `up`: gets an IPN notification with the state change, and prints a second device approval URL Either URL works, but this is annoying for the user. In this patch, we track whether the last printed URL was the device approval URL, and if so, we skip printing it a second time. Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-10-08tstest/integration: log all the output printed by `tailscale up`Alex Chan2-1/+4
Updates tailscale/corp#31476 Updates #17361 Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-10-08tstest/integration: test `tailscale up` when device approval is requiredAlex Chan3-101/+222
This patch extends the integration tests for `tailscale up` to include tailnets where new devices need to be approved. It doesn't change the CLI, because it's mostly working correctly already -- these tests are just to prevent future regressions. I've added support for `MachineAuthorized` to mock control, and I've refactored `TestOneNodeUpAuth` to be more flexible. It now takes a sequence of steps to run and asserts whether we got a login URL and/or machine approval URL after each step. Updates tailscale/corp#31476 Updates #17361 Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-10-08wgengine/magicsock: start peer relay path discovery sooner (#17485)Jordan Whited1-19/+19
This commit also shuffles the hasPeerRelayServers atomic load to happen sooner, reducing the cost for clients with no peer relay servers. Updates tailscale/corp#33099 Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-10-08go.toolchain.rev: bump Go to 1.25.2Brad Fitzpatrick11-7/+11
Updates tailscale/go#135 Change-Id: I89cfb49b998b2fd0264f8d5f4a61af839cd06626 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-08control/controlclient: add missing comment (#17498)Claus Lensbøl1-1/+1
Updates #cleanup Signed-off-by: Claus Lensbøl <claus@tailscale.com>
2025-10-08control/ts2021: fix data race during concurrent Close and conn endingBrad Fitzpatrick1-0/+1
Fixes tailscale/corp#33125 Change-Id: I9911f5059d5ebe42ecf7db9becb2326cca240765 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-08ipn/ipnlocal: use eventbus.SubscribeFunc in expiryManagerM. J. Fromberger1-23/+6
Updates #15160 Updates #17487 Change-Id: I8721e3ac1af505630edca7c5cb50695b0aad832a Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-08wgengine/magicsock: use eventbus.SubscribeFunc in ConnM. J. Fromberger1-50/+21
Updates #15160 Updates #17487 Change-Id: Ic9eb8d82b21d9dc38cb3c681b87101dfbc95af16 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-08wgengine/router: use eventbus.SubscribeFunc in linuxRouterM. J. Fromberger1-28/+12
Updates #15160 Updates #17487 Change-Id: Ib798e2321e55a078c8bd37f366fe4e73054e4520 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-08wgengine: use eventbus.SubscribeFunc in userspaceEngineM. J. Fromberger1-28/+11
Updates #15160 Updates #17487 Change-Id: Id852098c4f9c2fdeab9151b0b8c14dceff73b99d Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-08ipn/ipnlocal: fix data race on captiveCtx in enterStateLockedOnEntry (#17495)James 'zofrex' Sanderson1-2/+3
Updates #17491 Signed-off-by: James Sanderson <jsanderson@tailscale.com>
2025-10-08k8s-operator/sessionrecording: gives the connection to the recorder from the ↵Tom Meadows2-3/+12
hijacker a dedicated context (#17403) The hijacker on k8s-proxy's reverse proxy is used to stream recordings to tsrecorder as they pass through the proxy to the kubernetes api server. The connection to the recorder was using the client's (e.g., kubectl) context, rather than a dedicated one. This was causing the recording stream to get cut off in scenarios where the client cancelled the context before streaming could be completed. By using a dedicated context, we can continue streaming even if the client cancels the context (for example if the client request completes). Fixes #17404 Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
2025-10-08cmd/tsrecorder: adds sending api level logging to tsrecorder (#16960)Tom Meadows13-21/+1014
Updates #17141 Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
2025-10-08flake.nix: use tailscale go fork (#17486)Mike O'Driscoll1-6/+9
Move our nix flake to use Tailscale's go toolchain instead of upstream go. Fixes #17494 Signed-off-by: Mike O'Driscoll <mikeo@tailscale.com>
2025-10-07util/eventbus: add a function-based subscriber type (#17432)M. J. Fromberger3-77/+268
Originally proposed by @bradfitz in #17413. In practice, a lot of subscribers have only one event type of interest, or a small number of mostly independent ones. In that case, the overhead of running and maintaining a goroutine to select on multiple channels winds up being more noisy than we'd like for the user of the API. For this common case, add a new SubscriberFunc[T] type that delivers events to a callback owned by the subscriber, directly on the goroutine belonging to the client itself. This frees the consumer from the need to maintain their own goroutine to pull events from the channel, and to watch for closure of the subscriber. Before: s := eventbus.Subscribe[T](eventClient) go func() { for { select { case <-s.Done(): return case e := <-s.Events(): doSomethingWith(e) } } }() // ... s.Close() After: func doSomethingWithT(e T) { ... } s := eventbus.SubscribeFunc(eventClient, doSomethingWithT) // ... s.Close() Moreover, unless the caller wants to explicitly stop the subscriber separately from its governing client, it need not capture the SubscriberFunc value at all. One downside of this approach is that a slow or deadlocked callback could block client's service routine and thus stall all other subscriptions on that client, However, this can already happen more broadly if a subscriber fails to service its delivery channel in a timely manner, it just feeds back more immediately. Updates #17487 Change-Id: I64592d786005177aa9fd445c263178ed415784d5 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-07cmd/tailscaled: default state encryption off for incompatible args (#17480)Tom Proctor1-28/+38
Since #17376, containerboot crashes on startup in k8s because state encryption is enabled by default without first checking that it's compatible with the selected state store. Make sure we only default state encryption to enabled if it's not going to immediately clash with other bits of tailscaled config. Updates tailscale/corp#32909 Change-Id: I76c586772750d6da188cc97b647c6e0c1a8734f0 Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com>
2025-10-07ipn/localapi: dead code eliminate unreachable/useless LocalAPI handlers when ↵Brad Fitzpatrick3-53/+66
disabled Saves ~94 KB from the min build. Updates #12614 Change-Id: I3b0b8a47f80b9fd3b1038c2834b60afa55bf02c2 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-07ipn/ipnlocal: use named arguments for `mockControl.send()`Alex Chan2-38/+46
Updates #cleanup Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-10-07feature/linkspeed: move cosmetic tstun netlink code out to modular featureBrad Fitzpatrick15-30/+72
Part of making all netlink monitoring code optional. Updates #17311 (how I got started down this path) Updates #12614 Change-Id: Ic80d8a7a44dc261c4b8678b3c2241c3b3778370d Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-07wgengine/{magicsock,userspace,router}: move portupdates to the eventbus (#17423)Claus Lensbøl10-122/+83
Also pull out interface method only needed in Linux. Instead of having userspace do the call into the router, just let the router pick up the change itself. Updates #15160 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
2025-10-07ipn/ipnlocal: don't send LoginFinished unless auth was in progress (#17266)James 'zofrex' Sanderson2-1/+17
Before we introduced seamless, the "blocked" state was used to track: * Whether a login was required for connectivity, and therefore we should keep the engine deconfigured until that happened * Whether authentication was in progress "blocked" would stop authReconfig from running. We want this when a login is required: if your key has expired we want to deconfigure the engine and keep it down, so that you don't keep using exit nodes (which won't work because your key has expired). Taking the engine down while auth was in progress was undesirable, so we don't do that with seamless renewal. However, not entering the "blocked" state meant that we needed to change the logic for when to send LoginFinished on the IPN bus after seeing StateAuthenticated from the controlclient. Initially we changed the "if blocked" check to "if blocked or seamless is enabled" which was correct in other places. In this place however, it introduced a bug: we are sending LoginFinished every time we see StateAuthenticated, which happens even on a down & up, or a profile switch. This in turn made it harder for UI clients to track when authentication is complete. Instead we should only send it out if we were blocked (i.e. seamless is disabled, or our key expired) or an auth was in progress. Updates tailscale/corp#31476 Updates tailscale/corp#32645 Fixes #17363 Signed-off-by: James Sanderson <jsanderson@tailscale.com>
2025-10-06util/checkchange: stop using deephash everywhereBrad Fitzpatrick17-48/+365
Saves 45 KB from the min build, no longer pulling in deephash or util/hashx, both with unsafe code. It can actually be more efficient to not use deephash, as you don't have to walk all bytes of all fields recursively to answer that two things are not equal. Instead, you can just return false at the first difference you see. And then with views (as we use ~everywhere nowadays), the cloning the old value isn't expensive, as it's just a pointer under the hood. Updates #12614 Change-Id: I7b08616b8a09b3ade454bb5e0ac5672086fe8aec Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-06cmd/tailscaled: guard some flag work with buildfeatures checksBrad Fitzpatrick1-29/+35
Updates #12614 Change-Id: Iec6f15d33a6500e7b0b7e8f5c098f7c00334460f Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-06build_dist.sh: keep --extra-small making a usable build, add --minBrad Fitzpatrick1-0/+8
Historically, and until recently, --extra-small produced a usable build. When I recently made osrouter be modular in 39e35379d41fc788 (which is useful in, say, tsnet builds) after also making netstack modular, that meant --min now lacked both netstack support for routing and system support for routing, making no way to get packets into wireguard. That's not a nice default to users. (we've documented build_dist.sh in our KB) Restore --extra-small to making a usable build, and add --min for benchmarking purposes. Updates #12614 Change-Id: I649e41e324a36a0ca94953229c9914046b5dc497 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-06ipn/ipnlocal: fix another racy test (#17472)M. J. Fromberger1-2/+2
Some of the test cases access fields of the backend that are supposed to be locked while the test is running, which can trigger the race detector. I fixed a few of these in #17411, but I missed these two cases. Updates #15160 Updates #17192 Change-Id: I45664d5e34320ecdccd2844e0f8b228145aaf603 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-06feature/condlite/expvar: add expvar stub package when metrics not neededBrad Fitzpatrick10-10/+37
Saves ~53 KB from the min build. Updates #12614 Change-Id: I73f9544a9feea06027c6ebdd222d712ada851299 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-06wgengine/magicsock: add more handleNewServerEndpointRunLoop tests (#17469)Jordan Whited1-29/+166
Updates tailscale/corp#32978 Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-10-06appc,ipn/ipnlocal: receive AppConnector updates via the event bus (#17411)M. J. Fromberger5-267/+238
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>