Commit Graph
22 Commits
Author SHA1 Message Date
Harry Harpham 7ddbd84171 ipn/ipnlocal: ensure TestServeUnixSocket actually serves a Unix socket
The test sets up an HTTP-over-Unix server and a reverse proxy pointed at
this server, but prior to this change did not round-trip anything to the
backing server. This change ensures that we test code paths which proxy
Unix sockets for serve.

Fixes #19232
Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-04-03 14:15:15 -06:00
Harry Harpham 1e2fdfd745 tsnet: fix bug in closing multiple ServiceListeners at once
Prior to this change, closing multiple ServiceListeners concurrently
could result in failures as the independent close operations vie for the
attention of the Server's LocalBackend. The close operations would each
obtain the current ETag of the serve config and try to write new serve
config using this ETag. When one write invalidated the ETag of another,
the latter would fail. Exacerbating the issue, ServiceListener.Close
cannot be retried.

This change resolves the bug by using Server.mu to synchronize across
all ServiceListener.Close operations, ensuring they happen serially.

Fixes #19169

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-04-01 08:24:17 -06:00
Harry Harpham fed0df6498 tsnet: add test for advertising multiple Services
This is a regression test for #19166, in which it was discovered that
after calling Server.ListenService for multiple Services, only the
Service from the most recent call would be advertised.

The bug was fixed in 99f8039101

Updates #19166

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-04-01 08:01:14 -06:00
Harry HarphamandAlex Chan 61ac021c5d wgengine/magicsock: assume network up for tests
Without this, any test relying on underlying use of magicsock will fail
without network connectivity, even when the test logic has no need for a
network connection. Tests currently in this bucket include many in
tstest/integration and in tsnet.

Further explanation:

ipn only becomes Running when it sees at least one live peer or DERP
connection:
https://github.com/tailscale/tailscale/blob/0cc1b2ff76560ee4675909272fa37ba6b397744c/ipn/ipnlocal/local.go#L5861-L5866

When tests only use a single node, they will never see a peer, so the
node has to wait to see a DERP server.

magicsock sets the preferred DERP server in updateNetInfo(), but this
function returns early if the network is down.
https://github.com/tailscale/tailscale/blob/0cc1b2ff76560ee4675909272fa37ba6b397744c/wgengine/magicsock/magicsock.go#L1053-L1106

Because we're checking the real network, this prevents ipn from entering
"Running" and causes the test to fail or hang.

In tests, we can assume the network is up unless we're explicitly testing
the behaviour of tailscaled when the network is down. We do something similar
in magicsock/derp.go, where we assume we're connected to control unless
explicitly testing otherwise:
https://github.com/tailscale/tailscale/blob/7d2101f3520f16b86f2ed5e15f23c44d720534e6/wgengine/magicsock/derp.go#L166-L177

This is the template for the changes to `networkDown()`.

Fixes #17122

Co-authored-by: Alex Chan <alexc@tailscale.com>
Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-03-31 09:57:14 -06:00
Harry Harpham 4f43ad3042 tsnet: clean up state when Service listener is closed
Previous to this change, closing the listener returned by
Server.ListenService would free system resources, but not clean up state
in the Server's local backend. With this change, the local backend state
is now cleaned on close.

Fixes tailscale/corp#35860

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-03-25 10:16:29 -06:00
Harry Harpham 1794765cc6 tsnet: block rather than poll in setup for TestListenService
TestListenService needs to setup state (capabilities, advertised routes,
ACL tags, etc.). It is imperative that this state propagates to all nodes
in the test tailnet before proceeding with the test. To achieve this,
TestListenService currently polls each node's local backend in a loop.
Using local.Client.WatchIPNBus improves the situation by blocking until
a new netmap comes in.

Fixes tailscale/corp#36244

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-03-25 10:16:29 -06:00
Harry Harpham 47ef1a95db tsnet: use tstest.Shard in new tsnet tests
This helps us distribute tests across CI runners. Most tsnet tests call
tstest.Shard, but two recently added tests do not: tsnet.TestFunnelClose
and tsnet.TestListenService. This commit resolves the oversight.

Fixes tailscale/corp#36242

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-03-25 10:16:29 -06:00
Harry Harpham 299f1bf581 testcontrol: ensure Server.UpdateNode triggers netmap updates
Updating a node on a testcontrol server should trigger netmap updates to
all connected streaming clients. This was not the case previous to this
change and consequently caused race conditions in tests. It was possible
for a test to call UpdateNode and for connected nodes to never see the
update propagate.

Updates #16340
Fixes #18703

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-02-18 09:08:12 -07:00
Harry Harpham fbbf0d6669 tsconsensus: fix race condition in TestOnlyTaggedPeersCanBeDialed
TestOnlyTaggedPeersCanBeDialed has a race condition:
- The test untags ps[2] and waits until ps[0] sees this tag dropped from
  ps[2] in the netmap.
- Later the test tries to dial ps[2] from ps[0] and expects the dial to
  fail as authorization to dial relies on the presence of the tag, now
  removed from ps[2].
- However, the authorization layer caches the status used to consult peer
  tags. When the dial happens before the cache times out, the test fails.
- Due to a bug in testcontrol.Server.UpdateNode, which the test uses to
  remove the tag, netmap updates are not immediately triggered. The test
  has to wait for the next natural set of netmap updates, which on my
  machine takes about 22 seconds. As a result, the cache in the
  authorization layer times out and the test passes.
- If one fixes the bug in UpdateNode, then netmap updates happen
  immediately, the cache is no longer timed out when the dial occurs, and
  the test fails.

Fixes #18720
Updates #18703

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-02-17 14:39:02 -07:00
Harry Harpham 84ee5b640b testcontrol: send updates for new DNS records or app capabilities
Two methods were recently added to the testcontrol.Server type:
AddDNSRecords and SetGlobalAppCaps. These two methods should trigger
netmap updates for all nodes connected to the Server instance, the way
that other state-change methods do (see SetNodeCapMap, for example).

This will also allow us to get rid of Server.ForceNetmapUpdate, which
was a band-aid fix to force the netmap updates which should have been
triggered by the aforementioned methods.

Fixes tailscale/corp#37102

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-02-11 11:49:15 -07:00
Harry Harpham 6e44cb6ab3 tsnet: make ListenService examples consistent with other tsnet examples
Fixes tailscale/corp#36365

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-01-26 14:59:18 -07:00
Harry Harpham c062230cce tsnet: clarify that ListenService starts the server if necessary
Every other listen method on tsnet.Server makes this clarification, so
should ListenService.

Fixes tailscale/corp#36207
Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-01-22 13:39:19 -07:00
Harry Harpham 3840183be9 tsnet: add support for Services
This change allows tsnet nodes to act as Service hosts by adding a new
function, tsnet.Server.ListenService. Invoking this function will
advertise the node as a host for the Service and create a listener to
receive traffic for the Service.

Fixes #17697
Fixes tailscale/corp#27200
Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-01-16 15:28:31 -07:00
Harry Harpham 1b88e93ff5 ipn/ipnlocal: allow retrieval of serve config ETags from local API
This change adds API to ipn.LocalBackend to retrieve the ETag when
querying for the current serve config. This allows consumers of
ipn.LocalBackend.SetServeConfig to utilize the concurrency control
offered by ETags. Previous to this change, utilizing serve config ETags
required copying the local backend's internal ETag calcuation.

The local API server was previously copying the local backend's ETag
calculation as described above. With this change, the local API server
now uses the new ETag retrieval function instead. Serve config ETags are
therefore now opaque to clients, in line with best practices.

Fixes tailscale/corp#35857
Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-01-16 15:28:31 -07:00
Harry Harpham 87e108e10c docs: add instructions on referencing pull requests in commit messages
Updates #cleanup
Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-01-12 11:24:23 -07:00
Harry Harpham 78c8d14254 tsnet: use errors.Join and idiomatic field order
Updates #18376 (follow up on feedback)
Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-01-12 09:34:43 -07:00
Harry Harpham 3c1be083a4 tsnet: ensure funnel listener cleans up after itself when closed
Previously the funnel listener would leave artifacts in the serve
config. This caused weird out-of-sync effects like the admin panel
showing that funnel was enabled for a node, but the node rejecting
packets because the listener was closed.

This change resolves these synchronization issues by ensuring that
funnel listeners clean up the serve config when closed.

See also:
https://github.com/tailscale/tailscale/commit/e109cf9fdd405153a8d8c0ec52a87d7c8ce8689b

Updates #cleanup
Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-01-09 12:39:55 -07:00
Harry Harpham f9762064cf tsnet: reset serve config only once
Prior to this change, we were resetting the tsnet's serve config every
time tsnet.Server.Up was run. This is important to do on startup, to
prevent messy interactions with stale configuration when the code has
changed.

However, Up is frequently run as a just-in-case step (for example, by
Server.ListenTLS/ListenFunnel and possibly by consumers of tsnet). When
the serve config is reset on each of these calls to Up, this creates
situations in which the serve config disappears unexpectedly. The
solution is to reset the serve config only on the first call to Up.

Fixes #8800
Updates tailscale/corp#27200
Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-01-09 12:39:55 -07:00
Harry HarphamandGitHub 7de1b0b330 cmd/tailscale/cli: remove Services-specific subcommands from funnel (#18225)
The funnel command is sort of an alias for the serve command. This means
that the subcommands added to serve to support Services appear as
subcommands for funnel as well, despite having no meaning for funnel.
This change removes all such Services-specific subcommands from funnel.

Fixes tailscale/corp#34167

Signed-off-by: Harry Harpham <harry@tailscale.com>
2026-01-06 10:10:19 -06:00
Harry HarphamandGitHub ac74d28190 ipn/ipnlocal: add validations when setting serve config (#17950)
These validations were previously performed in the CLI frontend. There
are two motivations for moving these to the local backend:
1. The backend controls synchronization around the relevant state, so
   only the backend can guarantee many of these validations.
2. Doing these validations in the back-end avoids the need to repeat
   them across every frontend (e.g. the CLI and tsnet).

Updates tailscale/corp#27200

Signed-off-by: Harry Harpham <harry@tailscale.com>
2025-11-20 13:40:05 -06:00
Harry HarphamandGitHub 74f1d8bd87 cmd/tailscale/cli: unhide serve get-config and serve set-config (#17598)
Fixes tailscale/corp#33152

Signed-off-by: Harry Harpham <harry@tailscale.com>
2025-10-29 11:58:10 -05:00
Harry HarphamandGitHub 675b1c6d54 cmd/tailscale/cli: error when advertising a Service from an untagged node (#17577)
Service hosts must be tagged nodes, meaning it is only valid to
advertise a Service from a machine which has at least one ACL tag.

Fixes tailscale/corp#33197

Signed-off-by: Harry Harpham <harry@tailscale.com>
2025-10-20 15:36:31 -05:00