summaryrefslogtreecommitdiffhomepage
path: root/wgengine/userspace.go
AgeCommit message (Collapse)AuthorFilesLines
2026-01-23all: remove AUTHORS file and references to itWill Norris1-1/+1
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-22wgengine: send disco key via TSMP on first contact (#18215)Claus Lensbøl1-0/+9
When we have not yet communicated with a peer, send a TSMPDiscoAdvertisement to let the peer know of our disco key. This is in most cases redundant, but will allow us to set up direct connections when the client cannot access control. Some parts taken from: #18073 Updates #12639 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
2025-12-17net/netmon, wgengine/userspace: purge ChangeDelta.Major and address TODOs ↵Jonathan Nobels1-14/+31
(#17823) updates tailscale/corp#33891 Addresses several older the TODO's in netmon. This removes the Major flag precomputes the ChangeDelta state, rather than making consumers of ChangeDeltas sort that out themselves. We're also seeing a lot of ChangeDelta's being flagged as "Major" when they are not interesting, triggering rebinds in wgengine that are not needed. This cleans that up and adds a host of additional tests. The dependencies are cleaned, notably removing dependency on netmon itself for calculating what is interesting, and what is not. This includes letting individual platforms set a bespoke global "IsInterestingInterface" function. This is only used on Darwin. RebindRequired now roughly follows how "Major" was historically calculated but includes some additional checks for various uninteresting events such as changes in interface addresses that shouldn't trigger a rebind. This significantly reduces thrashing (by roughly half on Darwin clients which switching between nics). The individual values that we roll into RebindRequired are also exposed so that components consuming netmap.ChangeDelta can ask more targeted questions. Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
2025-12-10net/{packet,tstun},wgengine: update disco key when receiving via TSMP (#18158)Claus Lensbøl1-0/+17
When receiving a TSMPDiscoAdvertisement from peer, update the discokey for said peer. Some parts taken from: https://github.com/tailscale/tailscale/pull/18073/ Updates #12639 Co-authored-by: James Tucker <james@tailscale.com>
2025-12-09net/dns: retrample resolve.conf when another process has trampled it (#18069)Claus Lensbøl1-1/+1
When using the resolve.conf file for setting DNS, it is possible that some other services will trample the file and overwrite our set DNS server. Experiments has shown this to be a racy error depending on how quickly processes start. Make an attempt to trample back the file a limited number of times if the file is changed. Updates #16635 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
2025-12-02wgengine: fix TSMP/ICMP callback leakBrad Fitzpatrick1-0/+2
Fixes #18112 Change-Id: I85d5c482b01673799d51faeb6cb0579903597502 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-11-25net/tstun: add TSMPDiscoAdvertisement to TSMPPing (#17995)Claus Lensbøl1-2/+29
Adds a new types of TSMP messages for advertising disco keys keys to/from a peer, and implements the advertising triggered by a TSMP ping. Needed as part of the effort to cache the netmap and still let clients connect without control being reachable. Updates #12639 Signed-off-by: Claus Lensbøl <claus@tailscale.com> Co-authored-by: James Tucker <james@tailscale.com>
2025-11-21wgengine/userspace: run link change subscribers in eventqueue (#18024)Claus Lensbøl1-1/+7
Updates #17996 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
2025-11-13ipn/ipnlocal: remove all the weird locking (LockedOnEntry, UnlockEarly, etc)Brad Fitzpatrick1-0/+27
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-10wgengine: make getStatus a bit cheaper (less alloc-y)Brad Fitzpatrick1-6/+9
This removes one of the O(n=peers) allocs in getStatus, as Engine.getStatus happens more often than Reconfig. Updates #17814 Change-Id: I8a87fbebbecca3aedadba38e46cc418fd163c2b0 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-28wgengine/netlog: embed node information in network flow logs (#17668)Joe Tsai1-1/+4
This rewrites the netlog package to support embedding node information in network flow logs. Some bit of complexity comes in trying to pre-compute the expected size of the log message after JSON serialization to ensure that we can respect maximum body limits in log uploading. We also fix a bug in tstun, where we were recording the IP address after SNAT, which was resulting in non-sensible connection flows being logged. Updates tailscale/corp#33352 Signed-off-by: Joe Tsai <joetsai@digital-static.net>
2025-10-08feature/featuretags: make bird depend on advertiseroutesBrad Fitzpatrick1-1/+1
Updates #cleanup Change-Id: I87082919064a5652c0d976cadd6d159787bb224a Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-08net/dns, wgengine: use viewer/cloner for ConfigBrad Fitzpatrick1-5/+8
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 Fitzpatrick1-4/+18
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-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-07wgengine/{magicsock,userspace,router}: move portupdates to the eventbus (#17423)Claus Lensbøl1-8/+0
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-06util/checkchange: stop using deephash everywhereBrad Fitzpatrick1-17/+39
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-06feature/featuretags: add LazyWG modular featureBrad Fitzpatrick1-19/+33
Due to iOS memory limitations in 2020 (see https://tailscale.com/blog/go-linker, etc) and wireguard-go using multiple goroutines per peer, commit 16a9cfe2f4ce7d introduced some convoluted pathsways through Tailscale to look at packets before they're delivered to wireguard-go and lazily reconfigure wireguard on the fly before delivering a packet, only telling wireguard about peers that are active. We eventually want to remove that code and integrate wireguard-go's configuration with Tailscale's existing netmap tracking. To make it easier to find that code later, this makes it modular. It saves 12 KB (of disk) to turn it off (at the expense of lots of RAM), but that's not really the point. The point is rather making it obvious (via the new constants) where this code even is. Updates #12614 Change-Id: I113b040f3e35f7d861c457eaa710d35f47cee1cb Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-04wgengine: stop importing flowtrack when unusedBrad Fitzpatrick1-2/+1
Updates #12614 Change-Id: I42b5c4d623d356af4bee5bbdabaaf0f6822f2bf4 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-02feature/featuretags, all: add build features, use existing ones in more placesBrad Fitzpatrick1-1/+1
Saves 270 KB. Updates #12614 Change-Id: I4c3fe06d32c49edb3a4bb0758a8617d83f291cf5 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-01net/netmon: remove usage of direct callbacks from netmon (#17292)Claus Lensbøl1-1/+5
The callback itself is not removed as it is used in other repos, making it simpler for those to slowly transition to the eventbus. Updates #15160 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
2025-09-30feature, net/tshttpproxy: pull out support for using proxies as a featureBrad Fitzpatrick1-2/+4
Saves 139 KB. Also Synology support, which I saw had its own large-ish proxy parsing support on Linux, but support for proxies without Synology proxy support is reasonable, so I pulled that out as its own thing. Updates #12614 Change-Id: I22de285a3def7be77fdcf23e2bec7c83c9655593 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-09-29feature/logtail: pull logtail + netlog out to modular featuresBrad Fitzpatrick1-3/+3
Removes 434 KB from the minimal Linux binary, or ~3%. Primarily this comes from not linking in the zstd encoding code. Fixes #17323 Change-Id: I0a90de307dfa1ad7422db7aa8b1b46c782bfaaf7 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-09-24all: use buildfeatures.HasCapture const in a handful of placesBrad Fitzpatrick1-0/+4
Help out the linker's dead code elimination. Updates #12614 Change-Id: I6c13cb44d3250bf1e3a01ad393c637da4613affb Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-09-19wgengine: use eventbus.Client.Monitor to simplify subscriber maintenance ↵M. J. Fromberger1-23/+16
(#17203) This commit does not change the order or meaning of any eventbus activity, it only updates the way the plumbing is set up. Updates #15160 Change-Id: I40c23b183c2a6a6ea3feec7767c8e5417019fc07 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-09-17net/netmon: make ChangeDelta event not a pointer (#17112)Claus Lensbøl1-27/+49
This makes things work slightly better over the eventbus. Also switches ipnlocal to use the event over the eventbus instead of the direct callback. Updates #15160 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
2025-06-18ipn/ipnlocal,wgengine{/magicsock}: replace SetNetworkMap with eventbus (#16299)Jordan Whited1-1/+0
Same with UpdateNetmapDelta. Updates tailscale/corp#27502 Updates #15160 Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-05-12ipn/ipnlocal,wgengine: move (*tsdial.Dialer).SetRoutes() calls from ↵Nick Khyl1-0/+11
LocalBackend to userspaceEngine This avoids reconfiguring the dialer unless the router config has changed. Updates #12027 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-16net/netmon: publish events to event busDavid Anderson1-1/+1
Updates #15160 Signed-off-by: David Anderson <dave@tailscale.com>
2025-04-16{wgengine,util/portmapper}: add and plumb an event bus (#15359)M. J. Fromberger1-0/+1
Updates #15160 Change-Id: I2510fb4a8905fb0abe8a8e0c5b81adb15d50a6f8 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-04-16wgengine: plumb an event bus into the userspace engineM. J. Fromberger1-1/+16
Updates #15160 Change-Id: Ia695ccdddd09cd950de22abd000d4c531d6bf3c8 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-04-02net/tstun: add Plan 9 'tun' supportBrad Fitzpatrick1-0/+11
Updates #5794 Change-Id: I8c466cae25ae79be1097450a63e8c25c7b519331 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-04-01wgengine: return explicit lo0 for loopback addrs on sandboxed macOS (#15493)Jonathan Nobels1-0/+6
fixes tailscale/corp#27506 The source address link selection on sandboxed macOS doesn't deal with loopback addresses correctly. This adds an explicit check to ensure we return the loopback interface for loopback addresses instead of the default empty interface. Specifically, this allows the dns resolver to route queries to a loopback IP which is a common tactic for local DNS proxies. Tested on both macos, macsys and tailscaled. Forwarded requests to 127/8 all bound to lo0. Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
2025-01-24feature/capture: move packet capture to feature/*, out of iOS + CLIBrad Fitzpatrick1-2/+1
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>
2024-11-11all: use iterators over slice views moreBrad Fitzpatrick1-5/+4
This gets close to all of the remaining ones. Updates #12912 Change-Id: I9c672bbed2654a6c5cab31e0cbece6c107d8c6fa Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-11-01Fix MagicDNS on OpenBSDRenato Aguiar1-1/+1
Add OpenBSD to the list of platforms that need DNS reconfigured on link changes. Signed-off-by: Renato Aguiar <renato@renatoaguiar.net>
2024-09-26wgengine: make opts.Metrics mandatoryKristoffer Dalby1-1/+6
Fixes #13582 Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-09-25util/usermetrics: make usermetrics non-globalKristoffer Dalby1-2/+9
this commit changes usermetrics to be non-global, this is a building block for correct metrics if a go process runs multiple tsnets or in tests. Updates #13420 Updates tailscale/corp#22075 Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-09-05net/tstun: probe TCP GRO (#13376)Jordan Whited1-0/+1
Disable TCP & UDP GRO if the probe fails. torvalds/linux@e269d79c7d35aa3808b1f3c1737d63dab504ddc8 broke virtio_net TCP & UDP GRO causing GRO writes to return EINVAL. The bug was then resolved later in torvalds/linux@89add40066f9ed9abe5f7f886fe5789ff7e0c50e. The offending commit was pulled into various LTS releases. Updates #13041 Signed-off-by: Jordan Whited <jordan@tailscale.com>
2024-08-20net/tstun,wgengine{/netstack/gro}: refactor and re-enable gVisor GRO for ↵Jordan Whited1-3/+4
Linux (#13172) In 2f27319baf71681e221904d3a3ffe1badedc8e2e we disabled GRO due to a data race around concurrent calls to tstun.Wrapper.Write(). This commit refactors GRO to be thread-safe, and re-enables it on Linux. This refactor now carries a GRO type across tstun and netstack APIs with a lifetime that is scoped to a single tstun.Wrapper.Write() call. In 25f0a3fc8f6f9cf681bb5afda8e1762816c67a8b we used build tags to prevent importation of gVisor's GRO package on iOS as at the time we believed it was contributing to additional memory usage on that platform. It wasn't, so this commit simplifies and removes those build tags. Updates tailscale/corp#22353 Updates tailscale/corp#22125 Updates #6816 Signed-off-by: Jordan Whited <jordan@tailscale.com>
2024-08-03util/linuxfw: return nil interface not concrete typeMaisem Ali1-1/+1
It was returning a nil `*iptablesRunner` instead of a nil `NetfilterRunner` interface which would then fail checks later. Fixes #13012 Signed-off-by: Maisem Ali <maisem@tailscale.com>
2024-06-16net/ipset, wgengine/filter/filtertype: add split-out packagesBrad Fitzpatrick1-4/+5
This moves NewContainsIPFunc from tsaddr to new ipset package. And wgengine/filter types gets split into wgengine/filter/filtertype, so netmap (and thus the CLI, etc) doesn't need to bring in ipset, bart, etc. Then add a test making sure the CLI deps don't regress. Updates #1278 Change-Id: Ia246d6d9502bbefbdeacc4aef1bed9c8b24f54d5 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-06-04net/dns: don't set MatchDomains on Apple platforms when no upstream ↵Andrea Gottardo1-1/+1
nameservers available (#12334) This PR addresses a DNS issue on macOS as discussed this morning. Signed-off-by: Andrea Gottardo <andrea@gottardo.me>
2024-05-07ipn/ipnlocal, all: plumb health trackers in testsBrad Fitzpatrick1-0/+5
I saw some panics in CI, like: 2024-05-08T04:30:25.9553518Z ## WARNING: (non-fatal) nil health.Tracker (being strict in CI): 2024-05-08T04:30:25.9554043Z goroutine 801 [running]: 2024-05-08T04:30:25.9554489Z tailscale.com/health.(*Tracker).nil(0x0) 2024-05-08T04:30:25.9555086Z tailscale.com/health/health.go:185 +0x70 2024-05-08T04:30:25.9555688Z tailscale.com/health.(*Tracker).SetUDP4Unbound(0x0, 0x0) 2024-05-08T04:30:25.9556373Z tailscale.com/health/health.go:532 +0x2f 2024-05-08T04:30:25.9557296Z tailscale.com/wgengine/magicsock.(*Conn).bindSocket(0xc0003b4808, 0xc0003b4878, {0x1fbca53, 0x4}, 0x0) 2024-05-08T04:30:25.9558301Z tailscale.com/wgengine/magicsock/magicsock.go:2481 +0x12c5 2024-05-08T04:30:25.9559026Z tailscale.com/wgengine/magicsock.(*Conn).rebind(0xc0003b4808, 0x0) 2024-05-08T04:30:25.9559874Z tailscale.com/wgengine/magicsock/magicsock.go:2510 +0x16f 2024-05-08T04:30:25.9561038Z tailscale.com/wgengine/magicsock.NewConn({0xc000063c80, 0x0, 0xc000197930, 0xc000197950, 0xc000197960, {0x0, 0x0}, 0xc000197970, 0xc000198ee0, 0x0, ...}) 2024-05-08T04:30:25.9562402Z tailscale.com/wgengine/magicsock/magicsock.go:476 +0xd5f 2024-05-08T04:30:25.9563779Z tailscale.com/wgengine.NewUserspaceEngine(0xc000063c80, {{0x22c8750, 0xc0001976b0}, 0x0, {0x22c3210, 0xc000063c80}, {0x22c31d8, 0x2d3c900}, 0x0, 0x0, ...}) 2024-05-08T04:30:25.9564982Z tailscale.com/wgengine/userspace.go:389 +0x159d 2024-05-08T04:30:25.9565529Z tailscale.com/ipn/ipnlocal.newTestBackend(0xc000358b60) 2024-05-08T04:30:25.9566086Z tailscale.com/ipn/ipnlocal/serve_test.go:675 +0x2a5 2024-05-08T04:30:25.9566612Z ta Updates #11874 Change-Id: I3432ed52d670743e532be4642f38dbd6e3763b1b Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-05-06ipn/ipnlocal,net/tstun,wgengine: create and plumb jailed packet filterMaisem Ali1-0/+8
This plumbs a packet filter for jailed nodes through to the tstun.Wrapper; the filter for a jailed node is equivalent to a "shields up" filter. Currently a no-op as there is no way for control to tell the client whether a peer is jailed. Updates tailscale/corp#19623 Co-authored-by: Andrew Dunham <andrew@du.nham.ca> Signed-off-by: Maisem Ali <maisem@tailscale.com> Change-Id: I5ccc5f00e197fde15dd567485b2a99d8254391ad
2024-05-03ssh/tailssh: plumb health.Tracker in testBrad Fitzpatrick1-0/+2
In prep for it being required in more places. Updates #11874 Change-Id: Ib743205fc2a6c6ff3d2c4ed3a2b28cac79156539 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-05-02wgengine: add exit destination logging enable for wgengine logger (#11952)Claire Wang1-1/+2
Updates tailscale/corp#18625 Co-authored-by: Kevin Liang <kevinliang@tailscale.com> Signed-off-by: Claire Wang <claire@tailscale.com>
2024-04-27net/netns, net/dns/resolver, etc: make netmon required in most placesBrad Fitzpatrick1-2/+2
The goal is to move more network state accessors to netmon.Monitor where they can be cheaper/cached. But first (this change and others) we need to make sure the one netmon.Monitor is plumbed everywhere. Some notable bits: * tsdial.NewDialer is added, taking a now-required netmon * because a tsdial.Dialer always has a netmon, anything taking both a Dialer and a NetMon is now redundant; take only the Dialer and get the NetMon from that if/when needed. * netmon.NewStatic is added, primarily for tests Updates tailscale/corp#10910 Updates tailscale/corp#18960 Updates #7967 Updates #3299 Change-Id: I877f9cb87618c4eb037cee098241d18da9c01691 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-04-26health, all: remove health.Global, finish plumbing health.TrackerBrad Fitzpatrick1-2/+2
Updates #11874 Updates #4136 Change-Id: I414470f71d90be9889d44c3afd53956d9f26cd61 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-04-26ipn/{ipnlocal,localapi},wgengine{,/magicsock}: plumb health.TrackerBrad Fitzpatrick1-3/+9
Down to 25 health.Global users. After this remains controlclient & net/dns & wgengine/router. Updates #11874 Updates #4136 Change-Id: I6dd1856e3d9bf523bdd44b60fb3b8f7501d5dc0d Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>