conn25.go had grown to hold the extension, the Conn25 type, the config,
the DNS rewriting, and both the client and connector implementations.
Move the client struct and its methods to client.go, and the connector
struct and its methods to connector.go.
appAddr, transitIPExpiryEntry, and connectorTransitIPExpiry are used
only by the connector, so they move to connector.go. addrs moves to
client.go because it is a client-side concept, even though the
extension's send path in conn25.go and addrAssignments.go also refer
to it. Everything else stays in conn25.go.
Test functions covering client and connector behavior move to
client_test.go and connector_test.go correspondingly.
This is a pure code move: no declaration is added, removed, or edited,
and the relative order of everything is unchanged.
Updates #cleanup
Signed-off-by: Michael Ben-Ami <mzb@tailscale.com>
Contining the trend of making everything be optional that could
possibly be optional, this makes the magicsock UDP underlay transport
be optional. (mostly replacing a bunch of GOOS != "js" checks in the process)
Omitting udptransport (ts_omit_udptransport) makes magicsock DERP-only: no
UDP sockets, no advertised endpoints, and netcheck measures DERP latency
over HTTPS. Omitting only nattraversal keeps disco ping/pong to peers'
advertised endpoints but drops STUN, call-me-maybe, the peer relay client,
the endpoint tracker, and UDP lifetime probing.
Both are plain linker dead-code elimination via buildfeatures
constants. (as oppposed to moving the code all over into feature
packages and indirecting through hooks) The minimal linux/amd64
tailscaled shrinks by 258 KB without nattraversal and 561 KB without
both.
Updates #12614
Change-Id: Ife10804b48a168d9481e4321c18ed8fc85fa71f1
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The resnsend dnsproxyd command this package relays raw DNS messages
through was added in Android 10. On Android 9 and older the daemon
answers it with FrameworkListener's text "500 Command not recognized",
which we read as binary: "500 " passed the negative errno check and
"Comm" became the answer length, so every lookup failed with
"androiddns: bogus answer length 1131375981". That's what a tailcat
user hit on a Fire TV stick, which runs Android 9 under Fire OS 7.
Detect that text reply (a binary reply never starts with an ASCII
digit) and switch the process over to the daemon's older getaddrinfo
command, the one bionic's getaddrinfo proxies through. Parse the
single A or AAAA question out of the query, send the command with the
matching address family, and synthesize a DNS answer from the addrinfo
list that comes back, mapping EAI_NONAME to NXDOMAIN and EAI_NODATA to
an empty answer so Go's resolver produces its usual errors. Other
query types return an error saying the Android version can't answer
them.
The reply layout is the field-by-field one netd has used since
Android 6.0 (a 64-bit netd may serve a 32-bit client, so it stopped
sending the raw struct); Android 5.x's raw struct layout is detected
and rejected rather than guessed at. The format was verified against a
32-bit Fire OS 7.7.1.3 device (Android 9, API 28), where a tailcat
build with this change resolves names, fetches its DERP map over
HTTPS, and accepts a connection from another machine.
Updates tailscale/tailcat#126
Change-Id: I7062984c7ec8ce6caf737089e220ef2ca439dcc5
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The update/install localapi handler had no PermitWrite check, so any
local user who could reach the localapi socket could make the root
daemon self-update and restart itself. This has been the case since the
endpoint was added in November 2023.
Gate the handler behind PermitWrite so that only root or the operator
user can trigger a self-update, matching the other mutating handlers.
Updates tailscale/corp#48187
Change-Id: Iadfef939f5dab684652cd220e77de63b54bfca2f
Reported-by: Ben Carman <benthecarman@live.com>
Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
conn25 node attribute type
This node attribute configuration knob, when enabled, was bypassing two
peercap (tailscale.com/cap/conn25/<app_name>) checks while they were
under development and testing:
- PeerAPI DoH on the connector verifying the peercap includes the app in
query parameter of the request.
- PeerAPI ConnectorTransitIPRequest verifying the peercap includes the
app in the request.
With this change, we always perform those checks, and delete bypass
knob.
Updates tailscale/corp#40076
Updates tailscale/corp#48041
Signed-off-by: Michael Ben-Ami <mzb@tailscale.com>
The ts_omit_<name> build tags omit a feature at build time; there has
been no way to do the same at runtime. Some users (either proactively
or in response to a security announcement) might like a way to disable
a feature that's linked-in in their binaries that they're not using.
Then a mitigation announcement can say "set this env var" without
asking users to rebuild or wait for a new release.
This adds env var TS_DISABLE_FEATURE, a comma-separated list of
feature names to disable, and the listed set is reported by the
debug-optional-features LocalAPI endpoint next to the registered set.
The legacy per-feature knobs such as TS_DISABLE_SSH_SERVER and
TS_DISABLE_TAILDROP keep working independently.
A disabled feature behaves as if it had not been linked: it is absent
from feature.IsRegistered, its hooks are unset, and its extensions and
handlers are not registered. Three pieces make that happen:
* feature.Register now returns bool, false when disabled, and
feature packages gate their registration init on it. It was added
to the feature packages that never called it (including taildrop
and ssh), which also completes the picture reported by
debug-optional-features. taildrop, routecheck, favorites, and
serviceclientprefs had registration split across several inits and
now register from one gated init.
* ipnext.RegisterExtension ignores a disabled feature's extension.
* feature.Hook.Set and feature.Hooks.Add walk the call stack and
silently skip when the calling package under feature/<name> is
disabled. This covers sub-packages such as
feature/captiveportal/netcheckhook, which cannot call Register
themselves without colliding with their parent, and future
packages whose authors forget the gate.
ssh/tailssh's registrations moved from its inits into tailssh.Register,
called from feature/ssh's gated init. The aws and kube state stores and
syspolicy's Windows store registration are gated too.
feature/register_disable_test.go runs this test binary as a child
process (it links condregister, as tailscaled does) with
TS_DISABLE_FEATURE set to every registered feature at once, and fails
if any of them register anyway, so a feature that ignores the variable
cannot land.
Updates #12614
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I720af6ccab844ae060a9dfd1539fee577fd483e3
Query listening TCP and unconnected UDP sockets through inet_diag instead
of scanning the proc socket tables. Preserve process attribution and fall
back to proc on unsupported, interrupted, or invalid diagnostic dumps.
Cache missing protocol handlers as unsupported to avoid retrying every poll.
Read terminal dump flags directly: the pinned netlink library removes
NLMSG_DONE without checking NLM_F_DUMP_INTR. Keep socket creation and
recovery consistent with the proc namespace and close the poller when
its service discovery loop exits.
Include parser, request encoding, and errno classification tests.
Updates #10430
Updates #15492
Signed-off-by: JeremiahM37 <JeremiahM37@users.noreply.github.com>
This is a follow-up to #21029 (aa2681ac5f) to make it a bit stricter
and not cache DNS results until they've passed TLS cert validation,
to weed out DNS servers that are lying (like captive portals).
Because this is done via dnscache.TLSDialer we only catch the control
connection, but that's fine. That's all we need to come back alive
if DNS was down because real system DNS is itself over Tailscale.
The DERP connections should come via IPv4/IPv6 fields in the DERPMap.
And the logging connection isn't important; it'll buffer and catch up
later as needed when DNS is back up.
Updates #21028
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I75f176a0222f04ed52c9de1247deeed9b911f92c
Adds an opt-in, in-memory aggregator of recent connection-rejection
events (TSMP rejects received from peers, outbound TSMP rejects we emit
on ACL-blocked inbound flows, and pendopen timeouts) keyed by
(direction, proto, peer-address, reason). The aggregated data is exposed
over a new debug-rejects LocalAPI endpoint and a GET /debug/rejects c2n
endpoint, intended for future GUI/CLI consumption when diagnosing why a
connection failed.
Architecture:
- net/connreject holds the data types and a per-LocalBackend
Aggregator (LRU-bounded, default 256 entries on desktop / 32 on
mobile, per direction).
- feature/connreject is a self-registering ipnext.Extension that owns
one Aggregator per LocalBackend, installs note callbacks on the
tundev and engine, subscribes to OnSelfChange to flip the runtime
gate, and serves the LocalAPI/c2n endpoints.
- wgengine.Engine and *tstun.Wrapper each gain a SetConnRejectNote
setter; data-plane sites use a single atomic.Pointer load + nil
check, so the cost when no consumer is installed is one MOV.
Gating:
- Compile-time: ts_omit_connreject build tag (standard
feature/buildfeatures + condregister plumbing). Trims ~41 KB.
- Runtime: nodecap.ConnReject node attribute, off by default
at the control plane. May be removed once the feature is enabled
by default.
Updates CapabilityVersion to 146 (clients understand nodecap.ConnReject
and can serve GET /debug/rejects).
Adds Proto/Src/Dst accessors on flowtrack.Tuple (used by pendopen to
construct events without exposing the tuple's internals to the
aggregator).
Updates #1094
Updates #14802
Change-Id: I83e8f24a7e66fa2d158d128bd25fbe851134941b
Signed-off-by: James Tucker <james@tailscale.com>
Add a new modular dnsresolvecache feature that records every successful
DNS resolution from net/dnscache as a JSON file per hostname in
$statedir/dns-cache/, so a later boot with misconfigured DNS can still
find last-known-good IPs for critical hostnames like the control plane.
Files are rewritten only when their contents change, so a file's
modification time records when the answer last changed.
When regular DNS resolution fails, the disk cache is now consulted
before the DERP-based bootstrap DNS in net/dnsfallback. This is the
first step toward removing the DERP-based mechanism: new clientmetrics
(dnscache_disk_fallback_hit, dnscache_disk_fallback_miss,
dnscache_derp_fallback_ok, dnscache_derp_fallback_dial_ok) will tell us
when the DERP path no longer fires in the fleet and can be deleted.
The feature is linked into tailscaled by default (omittable with
ts_omit_dnsresolvecache) and is not included in tsnet.
Updates #21028
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I59228cbf68e3b48dfb1215cdd12bd8166ab14034
Instead of opening all DNS queries with conn25, only permit clients to
access domains of the apps that they have permission to use. Previous
changes ensure that clients report which app they are making a DNS query
for, simplifying the check.
Updates tailscale/corp#40076
Updates tailscale/corp#47585
Change-Id: I40fee220b3f190b2a0db9b3e6cc79f323ef16b73
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
Android denies app UIDs both NETLINK_ROUTE (golang/go#40569, #2293)
and /proc/net, so net.Interfaces always fails and netmon.New errors
out before a standalone binary can do anything. The Android app solves
this from Java via netmon.RegisterInterfaceGetter, but raw binaries
run under Termux or a rooted shell have no Java to lean on. This is
the second half of #21129, following the androiddns feature.
I added a netmon fallback hook, consulted only when no interface
getter was registered and net.Interfaces failed, and a new androidbin
feature (ts_omit_androidbin) that implements it: report a single
synthetic interface whose v4 and v6 addresses come from asking the
kernel to route an outbound UDP socket, which sends no packets and is
permitted in the app sandbox. That's enough for magicsock to discover
local endpoints. The fallback also requires runtime evidence of
Android (GOOS=android, or /dev/__properties__ existing for GOOS=linux
binaries running under an Android kernel), so it's inert on regular
Linux.
The androidbin feature also blank imports androiddns, and fixes a
third gap I found while testing: GOOS=linux binaries on Android have
an empty CA root pool, because Go's unix root loader doesn't know
Android's /system/etc/security/cacerts (the GOOS=android loader
does), so all TLS verification fails. On Android it points
SSL_CERT_DIR there unless the user already set it, as Termux's
ca-certificates package does.
The feature is on by default in tailscaled builds on Linux and
Android via condregister, and deliberately not linked into tsnet by
default; tsnet apps and other programs opt in with a blank import of
tailscale.com/feature/androidbin.
I verified on an Android 13 emulator with SELinux enforcing, running
GOOS=linux static binaries under the app UID (run-as), where
net.Interfaces fails with the exact netlinkrib permission denial from
the issue: netmon.New succeeds with the synthetic interface, and a
tailcat binary importing this feature does DNS via dnsproxyd, fetches
its DERP map over TLS using the Android cert store, completes STUN,
selects a DERP region, and prints its address.
Updates #21129
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: If7dbcbb825ecd24bcf6d9d64b1e334dd00700d51
Android doesn't have /etc/resolv.conf. This causes problems for people
running GOOS=linux binaries (or GOOS=android binaries without cgo, so
they don't use Android's bionic libc) in Termux, adb shell, etc.
(Go binaries built with cgo use bionic on Android: golang/go#10714)
16 years ago when I was on the Android team I added a system-wide DNS
cache (dnsproxyd) and made bionic query that, so each Android app
wasn't doing its own DNS resolution. That interface was never meant to
be stable, and I thought that code would be surely dead by now 16
years later, but apparently it lives on, and is more stable now: both
empirically (time, ossification?), and because of how Android's split system
updates work nowadays, the dnsproxyd lives on the other side of bionic,
so they seem to keep it pretty stable. The old bionic<->dnsproxyd APIs
I added 16 years ago are still there, but 8 years ago it got some additional
APIs to query by a DNS packet instead.
So use it! If we find ourselves on Android and without libc access
(and because we don't want to pull in ebitengine/purego with all its
side effects), just query the DNS server like bionic does.
This can be disabled in Linux binaries with ts_omit_androiddns.
Old links:
LineageOS/android_system_netd@007e987feehttps://android.googlesource.com/platform/system/netd/+/007e987fee7e815e0c4bc820f434a632b7a69a9d
("DNS proxy thread in netd.")
aosp-mirror/platform_bionic@a1dbf0b453https://android.googlesource.com/platform/bionic/+/a1dbf0b453801620565e5911f354f82706b0200d
("DNS proxy: the start. proxies getaddrinfo calls.")
Back then I found it cleaner to proxy at the getaddrinfo level rather
than speak in terms of DNS packets. The raw-packet resnsend command I
use here came eight years later, added in November 2018 for Android
10's android_res_nsend NDK API:
LineageOS/android_system_netd@c0c818f448https://android.googlesource.com/platform/system/netd/+/c0c818f448efa90ab1f9b1733fb86c5e22fb894c
("Add resNetworkSend cmd in DnsProxyListener")
Android 10 (codename Q, API level 29, released September 2019) is
therefore the minimum OS version for this to work.
I verified this against the DnsResolver module on an Android 13
emulator with SELinux enforcing, from the shell UID, with both a pure
Go GOOS=android binary and a static GOOS=linux binary: raw queries,
NXDOMAIN handling, the runtime Android detection, and a tailcat binary
reaching DERP with lookups visible in the daemon's logcat output, some
served from my 2010 DNS cache.
Updates #21129
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I0d63763e255a077e4e5745b3e64ba0d78dab6d69
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit bumps the wireguard-go dependency to incorporate changes to
the packet memory model and the tun.Device.Read and conn.ReceiveFunc I/O
interfaces. It updates their implementations accordingly.
These changes improve throughput in all measured benchmarks and reduce
peak RSS in six of eight cases. The two regressions will be addressed in
a follow-up commit that reduces peak RSS below the baseline measured at
1e69418. That work is kept separate to simplify review.
The following throughput and peak RSS benchmarks were performed with
iperf3 between two Intel i5-12400 nodes running Ubuntu 24.04 (Linux 6.8).
The UDP benchmarks did not use UDP GSO on the sender, so they were
roughly equivalent to single packet I/O through wireguard-go.
TCP/1 signifies one TCP stream; TCP/128 signifies 128 parallel TCP
streams.
Throughput (Mb/s)
Test 1e69418 After Change
TCP/1 10,371 11,354 +9.5%
TCP/128 7,886 8,404 +6.6%
UDP/1 2,111 2,853 +35.1%
UDP/128 1,747 2,235 +28.0%
Peak memory (VmHWM, kB)
Test Side 1e69418 After Change
TCP/1 TX 98,240 52,596 -46.5%
RX 287,748 73,384 -74.5%
TCP/128 TX 101,196 52,812 -47.8%
RX 290,420 63,620 -78.1%
UDP/1 TX 58,864 160,840 +173.2%
RX 137,516 49,900 -63.7%
UDP/128 TX 66,148 116,096 +75.5%
RX 154,384 56,556 -63.4%
Updates tailscale/corp#46716
Updates tailscale/corp#22467
Updates tailscale/corp#36989
Updates tailscale/corp#37878
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Use whatever traffic steering's notion of the best connector for the
client is, rather than picking arbitrarily.
Fixestailscale/corp#46766
Signed-off-by: Fran Bull <fran@tailscale.com>
So that when control notices a node isn't responding and sends that info
down in a netmap we will stop picking that node as a connector. This
doesn't provide great failover (it takes several minutes) but it's
better than not failing over at all.
Updates tailscale/corp#47250
Signed-off-by: Fran Bull <fran@tailscale.com>
The functions used to be used in ipn/ipnlocal but we changed that, so
the functions can be moved into feature/conn25 now.
Updates tailscale/corp#47250
Signed-off-by: Fran Bull <fran@tailscale.com>
Only allow TransitIPs to be allocated when the client has permission to
access the requested app.
Updates tailscale/corp#40076
Change-Id: Ib4b37afa25ffbdd220ba2c0fd9cfec8d5df5311f
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
Historically, when DERP regions were switched away from strings to
numeric identifiers in PR #14641, tailcfg.Node.HomeDERP was declared
as an int instead of its own type.
This PR declares a new tailcfg.DERPRegionID type, represented by an
int64, and converts the following fields to use this type:
- netcheck.Report.PreferredDERP
- netcheck.Report.RegionLatency
- netcheck.Report.RegionV4Latency
- netcheck.Report.RegionV6Latency
- tailcfg.DERPHomeParams.RegionScore
- tailcfg.DERPMap.Regions
- tailcfg.DERPNode.RegionID
- tailcfg.DERPRegion.RegionID
- tailcfg.NetInfo.PreferredDERP
- tailcfg.Node.HomeDERP
- tailcfg.PeerChange.DERPRegion
- tailcfg.PingResponse.DERPRegionID
Note that the original field was an int, while the new field is backed
by an int64. This change makes DERPRegionID the same size on both
32-bit and 64-bit architectures.
Fixes: #20165
Change-Id: Ic6f795a6d791dd16f756f246d5a02085443e212f
Signed-off-by: Simon Law <sfllaw@tailscale.com>
Let clients pin favorite devices, exit nodes, and services so GUIs can
surface & change them. Pins are stored per login profile in the new
favorites feature module, keyed per category; devices and exit nodes by
StableNodeID, services by ServiceName.
The item types live in a leaf package feature/favorites/pintype,
keeping them out of the core ipn hierarchy. Each category has
its own type (pintype.Device, pintype.ExitNode, pintype.Service).
Exposed over LocalAPI at GET/POST /localapi/v0/pins, where POST replaces
only the categories named in the request so a client can update one
category without clobbering the others. Pins are local to the device and
are not synced across a user's devices.
updates tailscale/corp#44836
Signed-off-by: Will Hannah <willh@tailscale.com>
Co-authored-by: Will Hannah <wph@Wills-Virtual-Machine.local>
Our tests are inconsistent in how they set environment variables and cleanup.
Missing cleanup logic can leak environment variable state across tests and
change the behaviour of subsequent tests.
This recently caused flakes in feature/acme, where `TestGetCertPEMWithValidity`
leaked `TS_CERT_SHARE_MODE` and `TestAsyncRenewalDedup` to fail inconsistently.
To fix the immediate flake and prevent future leaks, introduce a `SetenvForTest`
helper that handles setting and cleaning up environment variables in tests.
Fixes#20902
Change-Id: I9f8ef45ec875d66034cfd0054311bd69b67e2243
Signed-off-by: Alex Chan <alexc@tailscale.com>
The connector struct holds a map of peer+transitIP -> destinationIP that
it uses for routing traffic. The client registers new entries in the map
over the peer API.
Stop the transitIPs map from growing indefinitely by expiring entries
after 1 hour.
Updates tailscale/corp#38261
Signed-off-by: Fran Bull <fran@tailscale.com>
Currently we serialise ACME account setup and ACME issuances for domains
which don't yet have a valid certificate, but not for async renewals of
still-valid certificates.
This patch adds a check that we only have one async renewal for a domain
in-flight at a time, and a test that ensures we de-dupe these renewals.
Updates tailscale/corp#46420
Change-Id: Ibbaa537cd28b8adf238b5c9396403e845f95b7e7
Signed-off-by: Alex Chan <alexc@tailscale.com>
NewFlowTable pre-sized its two per-direction lookup maps to maxEntries.
The datapath handler creates a client table (10k flows) and a connector
table (100k flows) unconditionally at extension init, so every client
paid ~15.8 MiB of empty map buckets up front (measured on device, and
reproducible with a benchmark: 2x100k + 2x10k maps keyed by the 38-byte
flowtrack.Tuple).
On iOS the Network Extension has a hard 50 MiB jetsam limit. On large
tailnets the netmap and derived engine state need ~18 MiB of live heap
on top of the baseline, and this pre-allocation pushed the process over
the limit: the extension was killed (per-process-limit) seconds after
connecting, in a relaunch loop, making such tailnets unusable on iOS.
maxEntries is still enforced as a bound at insertion time; the maps now
grow on demand instead. On an iPhone 14 Pro Max joining a ~600 node
tailnet this took peak live heap during netmap ingest from 36.8 MiB to
24.3 MiB and the extension now connects and stays up with ~18 MiB of
headroom instead of being killed at 50 MiB.
Fixestailscale/corp#46408
Updates tailscale/corp#18514
Signed-off-by: James Tucker <james@tailscale.com>
Fix the small number of existing violations of this check, and enable it for
future runs. The fixes needed were:
- Clean up a few misspelled package names (probably renames).
- Clean up a few lexical nits ("Package x" instead of "The x package").
- Add lint directives to some files affected by build tag variance.
- Add a missing package comment and re-generate the k8s docs.
The lint overrides are a little ugly, but there are only a few places where we
need them, and it's probably worthwhile to enable the check on the rest of the
repo. Rather than replicate the docs around the build tag, I made the lint
diagnotics reference the "correct" file.
Updates #cleanup
Change-Id: I0d97f2f468542af456a0396cf9a023f04f23e436
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
Package tailcfg defines the types and constants used by the Tailscale
protocol, but since everything is all in one package, it’s difficult
to sift through the docs: https://pkg.go.dev/tailscale.com/tailcfg
We define and enumerate capabilities as string constants for
tailcfg.NodeCapability and tailcfg.PeerCapability. This PR extracts
them into their own packages:
- tailcfg.CapabilityFileSharing becomes nodecap.FileSharing
- tailcfg.NodeAttrOnlyTCP443 becomes nodecap.OnlyTCP443
- tailcfg.PeerCapabilityTaildrive becomes peercap.Taildrive
We originally intended for CapabilityFoo to grant an entitlement or
permission for Foo, and for NodeAttrBar to configure Bar in the
nodeAttrs section of the policy file. However, there was no technical
enforcement of this convention, so new capabilities have used the
NodeAttr prefix regardless of meaning. Therefore, this PR unifies
tailcfg.CapabilityFoo and tailcfg.NodeAttrBar into a single package as
nodecap.Foo and nodecap.Bar.
Ran `go fix -inline ./...` and committed the changes that replaced
uses of the tailcfg aliases with the authoritative ones.
Updates #20259
Change-Id: Ieb7e7e6c8247c39faf42fdf15c68cdc7c621c730
Signed-off-by: Simon Law <sfllaw@tailscale.com>
To prepare for enforcing permission to access an app, it is extremely
helpful if the client reports which app it expects the query is for,
instead of making the connector check all possible matching apps.
Updates tailscale/corp#40076
Change-Id: Ib41e0af4c0134d06dc4acda97a39c0a3adb88968
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
This patch pulls the printing and JSON-encoding out of
feature/tailnetlock/tslockjsonv1 into their callers, so that this
package only handles type conversions.
In cmd/tailscale/cli/tailnet-lock.go, it extracts the
printTailnetLockStatus function from runTailnetLockStatus to mirror
printTailnetLockLog and runTailnetLockLog.
Updates #17613
Signed-off-by: Simon Law <sfllaw@tailscale.com>
This patch renames the functions in feature/tailnetlock/tstestjsonv1
to remove stuttering. It also adds doc comments.
Updates #17613
Signed-off-by: Simon Law <sfllaw@tailscale.com>
This patch extracts the functions used to marshal the JSON output of
the `tailscale lock` subcommand.
Updates #17613
Signed-off-by: Simon Law <sfllaw@tailscale.com>
This patch extracts the JSON handling for the `tailscale lock`
subcommand from the jsonoutput package into its own tslockjsonv1
package.
Updates #17613
Signed-off-by: Simon Law <sfllaw@tailscale.com>
On switching from one tailnet with Connectors 2025 enabled to another,
clear the address assignments and flow tables from the previous tailnet.
They will not be useful in the new one (since the tailnet configuration
and nodes are different), and could blackhole traffic if both tailnets
happen to have a connector for the same domain.
Fixestailscale/corp#45619.
Signed-off-by: Naman Sood <mail@nsood.in>
Removing this check installs conn25 instance-level hooks whenever the
feature is built in. init-level hooks were always installed, but used
this guard to exit early.
Now all hooks, both instance-level and init-level rely on netmap
configuration (populated tailscale.com/app-connectors-experimental node
attribute, with non-empty apps) to not exit early.
The conn25-shutoff feature flag tells control not to send that node
attribute.
Fixestailscale/corp#39033
Signed-off-by: Michael Ben-Ami <mzb@tailscale.com>
not configured
We want all hooks and handlers to do as little as possible if the node
is not configured for conn25 or has no configured apps.
Updates tailscale/corp#39033
Signed-off-by: Michael Ben-Ami <mzb@tailscale.com>
Flatten the cmd/tailscale package hierarchy by extracting the
jsonoutput package out of the cmd/tailscale/cli package.
Updates #cleanup
Change-Id: I92f80db75b0328e82f1596b6a42f6f6ef5a94bfa
Signed-off-by: Simon Law <sfllaw@tailscale.com>
Introduce a per-tailnet shared ACME account key so that all ingress
ProxyGroup replicas on a tailnet present the same account identity to
Let's Encrypt. This lets renewals claim the ARI "replaces" exemption
from the 50-certs-per-week rate limit, surviving Pod restarts,
ProxyGroup recreation, and cluster migrations.
The operator provisions a "tailscale-acme-accounts" Secret in its
namespace, guarded by a finalizer and a deletion warning event, and
watched so it is recreated promptly if removed. Proxies migrate any
pre-existing per-pod key into the shared Secret on first boot, adopt
the shared key on subsequent boots, and restore it on cert writes if
the Secret was recreated empty. Certs are stamped with the fingerprint
of the issuing account so renewals skip the "replaces" claim when the
account doesn't match.
Opt-in per-ProxyGroup via the tailscale.com/share-acme-account
annotation, or operator-wide via OPERATOR_SHARED_ACME_ACCOUNT_KEY.
Updates #18251
Updates #20288
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
Add serviceclientprefs, an optional feature that stores and loads the
desktop clients' saved service launch preferences, one file per login
profile.
- Add GET|POST /localapi/v0/prefs/service-clients to load and save the
current profile's service client prefs.
- Add local client GetServiceClientPrefs and SetServiceClientPref that
call the new local api endpoint.
- Store the prefs with the ipn/store FileStore at
TailscaleVarRoot()/profile-data/<profileID>/service-client-prefs/<hex-encoded-key>,
so DeleteProfile cleans them up for free. Fall back to an in-memory
store when there's no var root.
- Register the feature and its local api route from build tagged files
so the whole thing drops out under ts_omit_serviceclientprefs.
- Add the serviceclient package holding Pref and Prefs (saved client,
username, database name, and last used time), so the local api client
and desktop apps can import the types without the feature machinery.
Change-Id: I340a99c1b332d181fb1556fbf3e8003bb3b95a08
Updates: https://github.com/tailscale/tailscale/issues/20429
Signed-off-by: Rollie Ma <rollie@tailscale.com>
An SNI ServerName with a trailing dot (e.g. "host.ts.net.") failed
cert lookup because stored cert names have no trailing dot. Per RFC
6066 section 3 the SNI HostName carries no trailing dot, but some
clients send a fully-qualified name with one.
Trim the trailing dot at the boundary in getCertPEMWithValidity so all
lookup paths (the GetCertificate hook, Serve, and the localapi) resolve
the dotted and dotless forms to the same certificate.
Fixes#10233
Signed-off-by: Saleh <root@lr0.org>
Previously it was conn25-state. The new name prepares for the ability to
add new endpoints behind the conn25/ prefix, and prepares for parity for
an upcoming c2n endpoint with the same name.
Updates tailscale/corp#40125
Signed-off-by: Michael Ben-Ami <mzb@tailscale.com>
And rename serveStateGet to serveLocalAPIStateGet to prepare for adding
a c2n handler that is backed by the same methods as the LocalAPI
handler.
Updates tailscale/corp#40125
Signed-off-by: Michael Ben-Ami <mzb@tailscale.com>