This adds the following helpers:
* WaitLength waits until the buffer is non-empty or a context is canceled.
It supports batchDelays so that even if data is ready, it blocks
until the delay is over. This is useful for how we upload logs for iOS,
where we deliberately wait a few minutes to reduce wakeup costs.
* DiscardOversize asynchronously discards data in the buffer
once it exceeds the specified maxSize. It takes in an optional frameLen
to ensure discarding maintains consistent frames in the buffer.
This avoids known problems with today's ring buffer where we can get
torn frames that lead to silent data corruption.
An alternative approach would be to synchronously delete data upon
an oversize condition at Write time, but there are two reasons
not to do that:
1. Doing requires teaching each Buffer implementation about
the concept of framing, which the interface deliberately avoids.
2. We want the write path to be extremely fast as we never want to
be blocking production logic. Going over maxSize momentarily is
considered a better tradeoff than synchronously blocking writes.
* StreamReader converts a non-blocking Buffer reader into a blocking one.
This exists primarily for debugging where you can simply stream
the entirety of a buffer to stdout.
We also adjust the package to avoid wrapping io.EOF and ErrEmpty
as those are sentinel errors with very specific meanings.
Updates tailscale/corp#21363
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This change contains the protocol changes needed to support
describing authorization for conn25 apps. As a temporary transition
measure during development, app configurations can disable authorization
enforcement.
Updates tailscale/corp#40076
Change-Id: I3183c10374aacb0048f6632c384f71f758c20f2f
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
Move away from mutating global, exported variables in wireguard-go. Use
device.Option's passed to device.NewDevice, instead. No functional
changes, just API cleanup in preparation of future changes.
Updates tailscale/corp#22467
Updates tailscale/corp#46396
Updates tailscale/corp#37878
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This adds a new ring buffer implementation that aims to replace
logtail.Buffer and the on-disk implementation in filch.Filch.
There are several problems with filch.Filch:
* Filching stderr should not be done at the buffer layer.
This makes structured representation within the buffer difficult
as arbitrary stderr data may unexpectedly appear,
which hinders attempts at more structured data.
* Log messages are assumed to be discreet lines rather than arbitrary bytes.
This makes it harder to switch the structured representation (e.g., using CBOR instead).
* Data that appears asynchronously through stderr never triggers a wake-up within logtail.
Consequently logs may never be uploaded.
* Relatedly, there is no mechanism for notifying that data has newly arrived in the buffer.
* There is no two-stage exfiltration. The TryReadLine method may or may not persist
the fact that the data was read. It arbitrarily depends on whether we cross
a magical file boundary in the dual-file approach.
A failed upload followed by a restart results in dropped logs.
A successful upload followed by a restart results in duplicated logs.
The new Buffer interface and VolatileBuffer implementation are
a step in the direction to resolving these problems.
* In the future, filching will output to a separate pipe
that we explicitly process the data for,
before putting it into the log buffer.
By processing the data, we can protect against stderr garbage being inserted
into the buffer unexpectedly breaking any structure.
* The Buffer.Peek and Buffer.DiscardUntil methods provide a way
to exfiltrate in a two-step manner.
When uploading, we peek at a chunk of data to upload.
When successful, we discard the data, ensuring that the buffer knows
not to provide that data again. The Len method can be used to suggest
to the logging service the amount of back pressure that exists.
Updates tailscale/corp#21363
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
We stop waiting to see if registry keys come available; this causes bad
interactions with the LocalBackend watchdog.
Instead we check the network interface for availability of AF_INET,
AF_INET6, and AF_NETBIOS. If no IP families are available on the
interface, we fail with an error. Otherwise we only attempt to configure
DNS for the address families that are actually enabled.
We also avoid changing any NetBIOS settings if AF_NETBIOS is disabled.
Fixes#46276
Change-Id: Ic7ae8a3dc810f4c428085f8b3ad905c6c32ae351
Signed-off-by: Aaron Klotz <aaron@tailscale.com>
Since #17567, FS.ChildAUMs scans and decodes every active AUM file.
Authority reconstruction and compaction call it repeatedly, making
filesystem work quadratic in the number of AUMs.
Build per-FS indexes of active AUM hashes and parent-to-child
relationships in one scan. Use the indexes for graph queries while
continuing to decode returned AUM values from disk. Invalidate the
indexes after mutations, but retain them for empty purges.
A production-sized 825-AUM benchmark improves from 124 seconds to
4 seconds on macOS with Defender and from 5.9 seconds to 34 milliseconds
on Linux ext3. The checked-in benchmark exercises the 2,000-AUM maximum
linear history accepted by the traversal guardrail.
RELNOTE: Avoid Tailnet Lock startup failures with large authority histories.
Fixes#20735
Change-Id: I088136bc2e9d1b6bfdecb223c069d42400c9f63d
Signed-off-by: Michael Renner <terrorobe@github.com>
The rendezvous hasher for traffic steering loadbalancing was flawed.
By plainly using the FNV-1a hash value, the result often reflected the
magnitude of the most significant bits in the hash seed, meaning the
hash function was not diffusive (aka missing the Avalanche Effect).
Popular wisdom seems to be that the output of FNV-1a should be mixed
with some large numbers to perturb more output bits. Borrow concepts
from other (Rust, Java) libraries by using the mix13 variant of 64-bit
finalizers by David Stafford.
Modify the fuzz test that asserts this fairness. Adjust a few
constants like client count and candidate count to more closely
reflect real-world scenarios and practical probabilities. Tighten
the bounds for distribution from 50% to +-20%.
Updates tailscale/corp#46471
Signed-off-by: Amal Bansode <amal@tailscale.com>
Previously, a delta update that drops a peer would not invalidate the digest
cache for that peer after deleting its cache entry. If a subsequent (later)
delta re-adds that peer with the same content, the digest cache would prevent
us from updating the persistent entry. Add a test to exercise this, and fix
the bug.
Updates #20795
Change-Id: I4a9ef03e8787a330d6395629251ee61ca2221fdd
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
This commit modifies the "generate" tool we use on the kubernetes operator
that produces helm chart and static manifest assets for CRDs.
Previously, this required always remembering to add new constants to
a `main.go` and did not have any mechanism to fail in CI if you forgot
to. Now this tool will iterate over all the CRDs and ensures that they're
in the places they're expected to be, with a test that will fail if they
are not.
This removes the requirement for remembering to add these constants
every time you have a new CRD.
Closes: #20594
Signed-off-by: David Bond <davidsbond93@gmail.com>
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
This commit changes how PeerRelay services are exposed on AWS. A Network
Load Balancer only forwards to targets in an availability zone enabled
on it, and spec.aws.elasticIPs pins each service to a single subnet,
which enables just one zone. A replica scheduled anywhere else silently
receives nothing while still reporting PeerRelayReady with an address in
status.endpoints.
Without spec.aws we now leave the subnet unpinned, so the AWS Load
Balancer Controller spreads the load balancer over every zone it finds,
and cross-zone load balancing is on by default so any of its addresses
reach the pod. Hostname resolution is no longer gated on the
eip-allocations annotation, which had left these unpinned services in
EndpointsPending forever, and a failure to resolve now logs at debug
since it is expected while a load balancer provisions.
Such a load balancer has an address per zone, and AWS bills for each, so
every one of them is now advertised rather than only the lowest sorted.
That also lets a peer reach the relay when one zone is unreachable.
status.endpoints gains address as a second list map key so a replica can
hold an entry per address; no field changes, so existing readers of
endpoints[].address keep working. Readiness counts the replicas that
have an endpoint rather than the entries, so a replica with several
addresses cannot mask one that has none.
The pods now serve containerboot's health check endpoint and the load
balancer is pointed at it over HTTP. A peer relay listens only on UDP,
so the default TCP check against the port the load balancer forwards
could never succeed and every target sat unhealthy while relaying
perfectly well. /healthz reports 200 once the device has tailnet
addresses, which is the condition that actually matters.
The CRD docs now describe spec.aws as the exception, note that it also
needs a ProxyClass pinning pods to the zone of the subnets it names, and
drop the claim that an Elastic IP has an availability zone of its own.
Fixes: https://github.com/tailscale/tailscale/issues/20833
Signed-off-by: David Bond <davidsbond93@gmail.com>
authkey.go references tsclient.Client in getAuthKey but never imported
the package, breaking main.
Updates #20544
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
The egressPodsReconciler (added in #14792) only sets the
tailscale.com/egress-services readiness condition on egress ProxyGroup
replica Pods that declare the corresponding readiness gate. However, the
gate was never actually added to the egress Pod template, so the
reconciler always hit its early-return and the readiness condition was
never set. This commit adds said readiness gate to the egress Pod template.
Updates #14326
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
ProxyGroup, Recorder, and PeerRelay each carried a near-identical copy of
the auth key re-issuance state machine (in-flight tracking, per-parent rate
limiting, stale-device cleanup). A bug fix had to land in three places and
could silently drift.
Extract it into a shared tailscaled.Reissuer, alongside the other tailscaled
workload helpers (NewAuthKey, AuthKeyFromConfigSecret, DeviceIDFromStateSecret)
that the callers already use. It owns its own mutex, tracks in-flight reissues
per replica keyed by parent, and rate-limits re-issuance per parent; the three
reconcilers drive it via EnsureState/RemoveState/ShouldReissue. The device
deletion helper is shared too, so the reissue state machine and its tests now
live in one place.
Updates #20544
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
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>
The unstamped Long() fallback (plain go build/install, no linker
stamps) always prefixed the buildvcs commit hash with "t". But that
hash describes the main module's repo, which for binaries built from a
repo that imports tailscale.com (e.g. Tailscale's proprietary repo) is
not the tailscale.com repo. That made e.g.
"1.103.0-dev20260811-t4bb67392c" ambiguous with the stamped scheme,
where "t" always means the tailscale.com commit and "g" the commit of
the repo the binary was built from.
Keep "t" when the main module is tailscale.com itself, and use "g"
otherwise, matching mkversion's meaning of the two prefixes.
Updates tailscale/corp#44945
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I42ed6dce6572854ead487b20b0889460c47d0f58
Package cobs implements Consistent Overhead Byte Stuffing (COBS),
a technique for reliable packet framing over serial byte streams.
This has future utility for storing a sequence of arbitrary log entries
on disk without needing to depend on intrinsic framing within
the log entries themselves (e.g., JSON or CBOR).
While more complicated, COBS is superior to offset-based framing
mechanisms as the null byte can be trivially used to demarcate
the boundaries of a frame. This makes COBS more resistant
against bit-corruption where a single corrupted offset
can make everything else in the file unreadable.
COBS makes it possible to resynchronize framing after a
corrupted section by simply searching for the next null.
Performance:
Benchmark/EncodeForward/Zeros-32 16341 76312 ns/op 13740.68 MB/s 0 B/op 0 allocs/op
Benchmark/EncodeReverse/Zeros-32 6326 188261 ns/op 5569.79 MB/s 0 B/op 0 allocs/op
Benchmark/DecodeForward/Zeros-32 16461 72140 ns/op 14535.28 MB/s 0 B/op 0 allocs/op
Benchmark/EncodeForward/NonZeros-32 41797 29155 ns/op 35965.56 MB/s 0 B/op 0 allocs/op
Benchmark/EncodeReverse/NonZeros-32 4792 248788 ns/op 4214.74 MB/s 0 B/op 0 allocs/op
Benchmark/DecodeForward/NonZeros-32 35790 34584 ns/op 30319.92 MB/s 0 B/op 0 allocs/op
Benchmark/EncodeForward/Random-32 23042 53727 ns/op 19516.64 MB/s 0 B/op 0 allocs/op
Benchmark/EncodeReverse/Random-32 3164 374590 ns/op 2799.26 MB/s 0 B/op 0 allocs/op
Benchmark/DecodeForward/Random-32 27241 58506 ns/op 17922.41 MB/s 0 B/op 0 allocs/op
EncodeReverse performance is notably slower than EncodeForward
because modern CPU architectures are not as optimized for
reading from memory in reverse.
However, reverse encoding is necessary if appending into
a dst buffer that is identical to the src buffer.
In such a case, the CPU performance hit is worth the benefit
of avoiding an intermediate allocation.
Speeds of GB/s is still plenty fast enough and
magnitudes faster than JSON or CBOR encoding.
Updates #17242
Updates tailscale/corp#21363
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
* tstest/natlab: test that a peer's name doesn't shadow a bare upstream name
With MagicDNS off, only suffixed names should be answered locally, but
since 1.102 quad-100 also answers a bare, unqualified name whenever a
tailnet device shares that name. It returns the device's Tailscale IP
instead of forwarding to the tailnet's global nameserver, leaving the
upstream record unreachable.
TestBareNameNotHijackedByPeer configures a global nameserver owning a
single-label name, adds a peer named to collide with it, and asserts the
client's lookup returns the upstream address. It queries via "tailscale
dns query" so the name stays a single label; a search domain completing
it would resolve a different name and pass regardless.
Add SplitDNSBareName to vnet's split-DNS zone to serve that name, and a
packet-level case asserting the fake server answers it.
Updates #20789
Signed-off-by: Brendan Creane <bcreane@gmail.com>
* tstest/natlab: check short names resolve via quad-100 when MagicDNS is on
TestMagicDNS asserted a peer's short name resolves, but through getent
with a search domain configured: libc completed it to the FQDN, so the
lookup never asked quad-100 for a single label. The bare-name path the
resolver takes when MagicDNS is enabled was untested.
Query the short name with "tailscale dns query" too, which asks for
exactly the name given. This is the enabled-MagicDNS mirror of
TestBareNameNotHijackedByPeer, and pins the other side of the condition
added in 1ec348784: a fix that dropped short names unconditionally,
rather than only when MagicDNS is disabled, now fails here.
Updates #20789
Signed-off-by: Brendan Creane <bcreane@gmail.com>
---------
Signed-off-by: Brendan Creane <bcreane@gmail.com>
nodeBackend.nodeByName should always contain both FQDNs and short names,
as it is used in different contexts, including UserDial DNS resolution, which should
be able to resolve unqualified DNS names regardless of the MagicDNS state.
However, net/dns/resolver.Resolver and, by extension, MagicDNSHosts
implementations should only resolve fully qualified domain names,
skipping short names when MagicDNS is disabled for the tailnet.
This fixes it in (*nodeBackend).nodeByFQDNLocked, which is only used
in the MagicDNS paths, and updates the tests.
Fixes#20789
Signed-off-by: Nick Khyl <nickk@tailscale.com>
The pre-push large-blob check diffed the pushed tree only against the
remote's old tree for the same ref. After rebasing a stale branch past
an unrelated large-file change on the default branch, that diff shows
the large file as changed even though the exact blob is already on the
remote via main, rejecting the push with a false positive.
Diff against every available base tree instead: the remote's old
commit for the ref plus the merge base with the remote's default
branch. Only flag a file that is a large addition relative to all
bases, so blobs the remote already has are not reported, while
genuinely new large files on the branch are still rejected.
Updates tailscale/corp#9863
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: Ia0c98fc1f5ab67a2913f948aeff605c72641ada7
This test was the repo's slowest at 60 seconds of wall time, all of it
spent sleeping: three of its subtests reach the unconditional 20 second
failover wait in kube/services.EnsureServicesAdvertised, despite using
a pure in-memory FakeLocalClient with no real control or I/O.
Run each subtest in a testing/synctest bubble so the wait elapses on
the fake clock instead. The test now completes in milliseconds.
Fixes#20792
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I3442815f7efcf6de740f893197ee0461ab049bb2
sendTCP dials through tsdial.Dialer and so honors UseNetstackForIP, but
sendUDP opened a host-stack socket via packetListener and never consulted
the dialer. In userspace networking mode (tsnet, or tailscaled
--tun=userspace-networking) there is no tun device, so a split-DNS query
to a tailnet resolver blackholed for the full udpRaceTimeout before the
TCP fallback answered it.
Add dialUDP, which picks between the netstack dialer and the existing
packetListener the same way tsdial.Dialer.dialOneUser does, and adapt the
connected netstack conn to nettype.PacketConn. sendUDP is otherwise
unchanged, so txid checks, SERVFAIL/REFUSED handling, TC flagging and EDNS
clamping are identical on both paths.
Unskips the UDP subtest of TestForwarderNetstackUpstream, which now
answers in ~300µs rather than 2s, and adds unit tests for the dispatch and
for truncation over the netstack path. TestSplitDNSToTailnetResolverUDP
covers the whole path end to end over real gVisor: two tsnet nodes with no
tun, one resolving a split-DNS name whose upstream is the other.
Fixes#20314
Signed-off-by: Brendan Creane <bcreane@gmail.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>
sendTCP dials through tsdial.Dialer and so honors UseNetstackForIP, but
sendUDP always uses a host-stack socket. In userspace networking mode
there is no route to the tailnet, so a split-DNS query to a tailnet
resolver only succeeds after falling back to TCP. The two subtests
differ only in transport, isolating that gap; the UDP one is skipped
pending a fix.
Updates #20314
Signed-off-by: Brendan Creane <bcreane@gmail.com>
The json/v2 prototype used to support a `format` tag option,
which has been removed for the initial release of json/v2 in Go 1.27.
The wrapper types in this package provide a way to avoid using
the `format` tag option for all existing use-cases.
The types are written to cooperate with other tag options
such as `string`, which may stringify JSON numbers.
We adjust cmd/vet/jsontags accordingly.
Updates #20220
Updates tailscale/corp#45953
Change-Id: Ie1fcea41dc30983e9acc43085f42a6e8ee49d26e
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
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>
* net/dns: scope quad-100 on macOS so DoH profiles aren't shadowed
On sandboxed macOS, an uncovered control ExtraRecord forced quad-100 to
be the primary resolver, proxying all public DNS and shadowing a user's
DoH system profile. Scope quad-100 to its match domains instead, adding
the uncovered host records to MatchDomains so they still resolve while
public names fall through to the OS resolver. quad-100 remains primary
only without a usable base resolver or with non-enumerable MagicDNS
host records.
fixestailscale/corp#45534
Signed-off-by: Will Hannah <willh@tailscale.com>
* net/dns: move scoped DNS behind an envknob
updates tailscale/corp#45534
Given the sensitivity of this change, let's stuff it behind
a control knob for a release.
Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
---------
Signed-off-by: Will Hannah <willh@tailscale.com>
Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
Co-authored-by: Jonathan Nobels <jonathan@tailscale.com>
The sysctler init container shells out to sysctl to turn on IP
forwarding for non-userspace proxies. That binary ships in the
procps-ng package, which Alpine has but Red Hat's UBI does not, so
on UBI the init container exits 127 and every proxy Pod is stuck in
PodInitializing and never registers a device.
Updates: https://github.com/tailscale/corp/issues/45981
Updates: https://github.com/tailscale/corp/issues/44443
Signed-off-by: David Bond <davidsbond93@gmail.com>
Add a second fake DNS server (4.11.4.12) serving a zone the default one
doesn't, so a split-DNS route can be verified: resolving that name proves the
query was forwarded there.
Tailscale implements a split-DNS route two ways, and a test covers each. When
the OS resolver supports split DNS and every route shares one resolver set,
tailscaled hands the OS that resolver directly and quad-100 stays out of the
query path; TestSplitDNSOSForwarded covers this, reaching the split resolver
over a subnet route as a real deployment would. Otherwise the OS is pointed at
quad-100, which forwards per-domain itself; TestSplitDNS covers this against
both the systemd-resolved and direct backends, along with the other ways a
lookup resolves -- answered locally by quad-100 from an extra record or from the
netmap, and unrouted names still going to the machine's normal resolver.
TestSplitDNSNoMagicDNS covers split DNS on a tailnet with MagicDNS off, which
the two above leave out: one has mixed resolver sets but MagicDNS on, the other
MagicDNS off but a single resolver set. Together those conditions take a
distinct path through compileConfig, where tailscaled reads the OS base
resolver config rather than scoping quad-100 to a match domain.
Both arrangements produce the same answers, so each test also asserts the
guest's resolver state to prove which one it exercised.
Fixestailscale/corp#44798
Signed-off-by: Brendan Creane <bcreane@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This reverts commit 7e01825e51.
The change was merged to main accidentally. Reverting so it can go
back through review before landing again.
updates tailscale/corp#45534
Signed-off-by: Brendan Creane <bcreane@gmail.com>
* net/dns: scope quad-100 on macOS so DoH profiles aren't shadowed
On sandboxed macOS, an uncovered control ExtraRecord forced quad-100 to
be the primary resolver, proxying all public DNS and shadowing a user's
DoH system profile. Scope quad-100 to its match domains instead, adding
the uncovered host records to MatchDomains so they still resolve while
public names fall through to the OS resolver. quad-100 remains primary
only without a usable base resolver or with non-enumerable MagicDNS
host records.
fixestailscale/corp#45534
Signed-off-by: Will Hannah <willh@tailscale.com>
* net/dns: move scoped DNS behind an envknob
updates tailscale/corp#45534
Given the sensitivity of this change, let's stuff it behind
a control knob for a release.
Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
---------
Signed-off-by: Will Hannah <willh@tailscale.com>
Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
Co-authored-by: Jonathan Nobels <jonathan@tailscale.com>
This commit adds a new `--base-image` flag to the e2e test suite
so that tests can build the operator and operator accessories
with a different base docker image. We want this so that we can
try things out with red hat's UBI as part of getting the operator
up and running on openshift clusters.
We can then modify the e2e test runner to use a matrix for normal
alpine base and redhat's.
Updates: https://github.com/tailscale/corp/issues/45981
Updates: https://github.com/tailscale/corp/issues/44443
Signed-off-by: David Bond <davidsbond93@gmail.com>
Both RoutableIPs and RequestTags act as a set of values. There have been
cases of misconfigured IAC populating duplicate values, resulting in
more data being sent to control than needs to be.
Updates tailscale/corp#44607
Signed-off-by: Evan Lowry <evan@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>
The Helm chart hardcoded the operator's Deployment, ServiceAccount,
Role, and RoleBinding names to "operator".
Adds a standard _helpers.tpl with name/fullname template functions and
use them for the operator's resources, including the oauth Secret and
the cluster-scoped ClusterRole/ClusterRoleBinding. When neither
nameOverride nor fullnameOverride is set, the fullname resolves to the
historical hardcoded names rather than the release name, so existing
installations upgrade with no resource renames; rendering with default
values is byte-identical to before.
Fixestailscale/tailscale#18232
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
The nameserver Deployment created for a DNSConfig was the only
operator-managed workload with no way to configure imagePullSecrets, so its
pods could not pull the nameserver image from a private registry.
Adds imagePullSecrets to NameserverPod and thread it through to the nameserver
Deployment pod spec.
Updates #16772
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
The Helm chart only applied imagePullSecrets to the operator Deployment's
pod spec, so proxy pods (which use a different ServiceAccount) never
received them and could not pull images from private registries.
Apply imagePullSecrets to the operator, proxies, and kube-apiserver-auth-proxy
ServiceAccounts.
Updates #16772
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
0eb38dc2e (#20561) made peer capability resolution return nothing for
peers with UnsignedPeerAPIOnly set, so that a possibly malicious
control server can't grant capabilities to peers outside the tailnet
lock authority. But Tailscale Funnel ingress nodes are unsigned by
design, and control intentionally grants them
PeerCapabilityIngress, which the peerapi /v0/ingress handler requires.
The result was that every Funnel connection was rejected with a 403
"denied; no ingress cap".
Instead of denying all capabilities to unsigned peers, allowlist
PeerCapabilityIngress specifically. It only permits ingress requests
over the PeerAPI, which unsigned peers can already reach, and the
node only serves them for targets explicitly configured for Funnel.
The tsnet TestFunnel didn't catch the regression because its fake
ingress peer was a normal signed peer. Teach testcontrol to mark a
node as UnsignedPeerAPIOnly (excluding such nodes from traffic-
permitting filter rules, as real control does, so clients don't
discard the packet filter) and make TestFunnel use it so the test
now exercises the same capability checks as production Funnel
traffic.
Updates tailscale/corp#46053
Updates #20739
Change-Id: I3f6b8e2a94d1c07b5a2e9d84f16c30aa79e5d21b
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit adds a new end-to-end test for the `PeerRelay` custom
resource.
This test is currently quite limited due to the fact that we are running
our tests within a kind cluster within github actions. This means it's
not really possible to give the peer relays a proper public IP address
via the `LoadBalancer` type services that we spin up.
That being said, we intend to expand our e2e test suite with actual
real clusters in future so this can be expanded upon at a later date.
For now, this test spins up a single and multi-replica deployment of
a peer relay and confirms that it has been registered with control
and is configured to act as a peer relay.
This test also caught a small bug where the server URL was not being
passed into the peer relay's configuration, which has been fixed here.
Closes: https://github.com/tailscale/corp/issues/45731
Closes: https://github.com/tailscale/corp/issues/45737
Signed-off-by: David Bond <davidsbond93@gmail.com>
The license header test walked the whole tree, so scratch files,
worktrees, and other untracked local files made "go test ." fail in a
developer checkout. Ask git for the set of tracked files and only
check those, falling back to checking everything (as before) when the
tree is not a git checkout, such as in a release tarball.
Fixes#20740
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I9f3a7c21e5b804d6a2f4c8e19d7b53a6e0c412fd
LocalBackend.Shutdown waits for the ACME refresh loop and active SSH
sessions. Both can be blocked acquiring LocalBackend.mu, so waiting while
holding that mutex deadlocks shutdown.
Detach the SSH server under the mutex, then stop both subsystems after
releasing it. Prevent their work from restarting once shutdown begins, and
serialize repeated Shutdown calls with sync.Once.
Add regression tests that verify subsystem shutdown runs without
LocalBackend.mu held.
Updates tailscale/corp#45964
Change-Id: I37ead4f26fbfb5703a83882668d98a8862ba7d67
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The ts_omit_unixsocketidentity variant of GetConnIdentity never
performs the *net.UnixConn type assertion, so ConnIdentity.isUnixSock
stays false. ipnserver's Permissions only grants local API access to
unix socket connections, so with this build tag every local API request
is denied read and write access ("status access denied") and the CLI
cannot talk to the daemon at all in --extra-small/--min builds.
Mirror the type assertion from the peercred variant so the omitted
identity build behaves as intended (everyone is an admin when unix
socket identities are compiled out).
Signed-off-by: loowr <loowr@proton.me>
We'll need this in corp at least, which means we need this here.
Updates #20220
Change-Id: I5dbf93f2b9ce05658193fc8ba61eb61185637521
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Commit 33042fb97 (go.mod: bump sigs.k8s.io/controller-runtime to
v0.23.3) was based on a stale tree and accidentally reverted the
staticcheck bump from 7eeb62415 back to v0.7.0. That version's IR
builder panics on the Go 1.27 standard library (unexpected expr:
*ast.KeyValueExpr), breaking staticcheck CI on the Go 1.27 test
branch. Everything else in that commit was intentional k8s ecosystem
upgrades; staticcheck was the only collateral revert.
Updates #20220
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I763a3dcc29e592adcf6979c80d6e720b02c0bb09