* ipn/ipnlocal: fix cache update for peers deleted by netmap deltas (#20851) After a netmap delta is applied, we scan the mutations for affected peers and update the cache (if enabled) for those peers. For removals in particular, we were relying on the node backend to resolve node IDs (provided by the delta mutation) to stable IDs. Prior to65fd320athis happened to work because the node backend would hold on to all the peers mentioned by the previous full netmap, even after applying deltas. But that was essentially accidental, and once we fixed it not to do that, these lookups no longer worked. We need the stable ID, since that is how the cache is keyed, and now that they're no longer pinned, we were not properly evicting removed peers from the cache. To fix this, capture removed peer stable IDs while applying mutations to the node backend, instead of trying to look them up afterward. Updates #20796 Change-Id: I14ded78eaf9657645f0869a52460fd3cd86edba6 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com> (cherry picked from commitf3552c29c0) * ipn/ipnlocal: don't evict another node's index entries on netmap deltas When applying netmap deltas, nodeBackend evicted its index entries (nodeByAddr, nodeByKey, nodeByWGString, nodeByStableID, nodeByName) derived from a node's last-known value without checking that the entry still pointed at that node. Control can reassign a churning ephemeral peer's Tailscale IP (or MagicDNS name) to a newer peer and deliver the new peer's upsert before the old peer's removal, either in an earlier MapResponse or reordered within one batch by the NodeID sort in netmap.MutationsFromMapResponse. The removal then wiped the new owner's entry. The peers map itself stayed correct in every ordering, so WireGuard kept the peer and handshakes succeeded, but WhoIs lookups by IP failed until the next full netmap rebuilt the indexes. On App Connectors that surfaced as "peerapi: unknown peer" and refused DNS connections from affected clients, with a toggle of Tailscale (forcing a full netmap) as the only recovery. Make every index eviction conditional on the entry still mapping to the node being removed or replaced, and add a regression test covering the cross-batch, intra-batch, and upsert-eviction orderings. Also add an end-to-end test in tstest/integration showing that a MapResponse reusing an address is handled incrementally rather than as a full netmap, and that LocalBackend.WhoIs still resolves the reused address afterwards, which is the lookup PeerAPI makes before it accepts a connection. Updates tailscale/corp#47435 Co-authored-by: Brendan Creane <bcreane@gmail.com> Signed-off-by: Brendan Creane <bcreane@gmail.com> Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I3f8c2a9d41e07b6a5cd2e94f78b013c6ad2f5e91 (cherry picked from commit2ae2808b64) * ipn/ipnlocal: preserve peer deltas on expiry Refresh the expiry timer netmap from the live peer state before reinstalling it, preventing delta updates from being rolled back. Updates tailscale/corp#47686 Change-Id: Idc738acea82bab5a8ba772084a41e55b38a06bcc Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> (cherry picked from commit0640312e51) * control/controlclient: replay user profiles on delta peer upserts A full netmap carries only the profiles of users with a currently visible peer (netmapForResponse), and nodeBackend replaces its live profile set wholesale on every full netmap install. A full netmap that arrives while a user has no visible peer therefore drops that user's profile downstream. When a peer of that user later returns as an incremental upsert, control does not resend the profile, because MapResponse.UserProfiles has carried only new or updated profiles since mapver 5. The upsert indexes the node by address and key, so WireGuard admits its traffic, but WhoIs then fails one step later at the user profile lookup, surfacing as "peerapi: unknown peer" until the next full netmap. It is a second, independent cause of the symptom fixed by the recent index eviction change. mapSession.lastUserProfile holds the profile the whole time, so when handling a response incrementally, also deliver the profiles of upserted peers' users (and sharers) from that store, before the mutations that reference them. The backport adapts the new tests to this branch's extra viaTSMP parameter on handleNonKeepAliveMapResponse. Updates tailscale/corp#47435 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I9c4b2f6a8e0d47d3b1a5c2e7f4098d61b23a7c50 (cherry picked from commit5201273aec) --------- Signed-off-by: M. J. Fromberger <fromberger@tailscale.com> Signed-off-by: Brendan Creane <bcreane@gmail.com> Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Co-authored-by: M. J. Fromberger <fromberger@tailscale.com> Co-authored-by: Brendan Creane <bcreane@gmail.com>
Tailscale
Private WireGuard® networks made easy
Overview
This repository contains the majority of Tailscale's open source code.
Notably, it includes the tailscaled daemon and
the tailscale CLI tool. The tailscaled daemon runs on Linux, Windows,
macOS, and to varying degrees
on FreeBSD and OpenBSD. The Tailscale iOS and Android apps use this repo's
code, but this repo doesn't contain the mobile GUI code.
Other Tailscale repos of note:
- the Android app is at https://github.com/tailscale/tailscale-android
- the Synology package is at https://github.com/tailscale/tailscale-synology
- the QNAP package is at https://github.com/tailscale/tailscale-qpkg
- the Chocolatey packaging is at https://github.com/tailscale/tailscale-chocolatey
For background on which parts of Tailscale are open source and why, see https://tailscale.com/opensource/.
Using
We serve packages for a variety of distros and platforms at https://pkgs.tailscale.com.
Other clients
The macOS, iOS, and Windows clients use the code in this repository but additionally include small GUI wrappers. The GUI wrappers on non-open source platforms are themselves not open source.
Building
We always require the latest Go release, currently Go 1.26. (While we build releases with our Go fork, its use is not required.)
go install tailscale.com/cmd/tailscale{,d}
If you're packaging Tailscale for distribution, use build_dist.sh
instead, to burn commit IDs and version info into the binaries:
./build_dist.sh tailscale.com/cmd/tailscale
./build_dist.sh tailscale.com/cmd/tailscaled
If your distro has conventions that preclude the use of
build_dist.sh, please do the equivalent of what it does in your
distro's way, so that bug reports contain useful version information.
Bugs
Please file any issues about this code or the hosted service on the issue tracker.
Contributing
PRs welcome! But please file bugs. Commit messages should reference bugs.
We require Developer Certificate of
Origin
Signed-off-by lines in commits.
See commit-messages.md (or skim git log) for our commit message style.
About Us
Tailscale is primarily developed by the people at https://github.com/orgs/tailscale/people. For other contributors, see:
- https://github.com/tailscale/tailscale/graphs/contributors
- https://github.com/tailscale/tailscale-android/graphs/contributors
Legal
WireGuard is a registered trademark of Jason A. Donenfeld.