Commit Graph

834 Commits

Author SHA1 Message Date
Mario Minardi 6587cafb3f cmd/tailscale: use advertise tags from prefs for OAuth and id federation
Use the parsed and validated advertise tags value from prefs instead of
doing a strings.Split on the raw tags value as an input to the OAuth and
identity federation auth key generation methods.

The previous strings.Split method would return an array with a single
empty string element which would pass downstream length checks on the
tags argument before eventually failing with a confusing message when
hitting the API.

Fixes https://github.com/tailscale/tailscale/issues/18617

Signed-off-by: Mario Minardi <mario@tailscale.com>
2026-02-05 12:50:48 -07:00
Brad Fitzpatrick 40cd54daf7 cmd/tailscale: remove dep on clientupdate package if feature is omitted
We already had a featuretag for clientupdate, but the CLI wasn't using
it, making the "minbox" build (minimal combined tailscaled + CLI
build) larger than necessary.

Updates #12614

Change-Id: Idd7546c67dece7078f25b8f2ae9886f58d599002
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-02-04 10:44:48 -08:00
Andrew Lytvynov ae95d8d222 cmd/tailscale: fix sanitizeOutput and add a test (#18589)
Follow up from https://github.com/tailscale/tailscale/pull/18563 which I
totally botched.

Updates #18562

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
2026-02-02 15:38:40 -08:00
Brad Fitzpatrick 8736fbb754 cmd/tailscale/cli: add 'wait' listening subcommand and ip --assert=<ip>
This provides a mechanism to block, waiting for Tailscale's IP to be
ready for a bind/listen, to gate the starting of other services.

It also adds a new --assert=[IP] option to "tailscale ip", for services
that want extra paranoia about what IP is in use, if they're worried about
having switched to the wrong tailnet prior to reboot or something.

Updates #3340
Updates #11504

... and many more, IIRC

Change-Id: I88ab19ac5fae58fd8c516065bab685e292395565
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-02-02 15:19:06 -08:00
Andrew Lytvynov db96e52d6f cmd/tailscale/cli: redact auth keys in FlagSet output (#18563)
Running a command like `tailscale up --auth-key tskey-foo --auth-key tskey-bar` used to print

```
invalid value "tskey-bar" for flag -auth-key: flag provided multiple times
```

but now we print

```
invalid value "tskey-REDACTED" for flag -auth-key: flag provided multiple times
```

Fixes #18562

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
2026-01-30 09:00:46 -08:00
Andrew Dunham bcceef3682 cmd/tailscale/cli: allow fetching keys from AWS Parameter Store
This allows fetching auth keys, OAuth client secrets, and ID tokens (for
workload identity federation) from AWS Parameter Store by passing an ARN
as the value. This is a relatively low-overhead mechanism for fetching
these values from an external secret store without needing to run a
secret service.

Usage examples:

    # Auth key
    tailscale up \
      --auth-key=arn:aws:ssm:us-east-1:123456789012:parameter/tailscale/auth-key

    # OAuth client secret
    tailscale up \
      --client-secret=arn:aws:ssm:us-east-1:123456789012:parameter/tailscale/oauth-secret \
      --advertise-tags=tag:server

    # ID token (for workload identity federation)
    tailscale up \
      --client-id=my-client \
      --id-token=arn:aws:ssm:us-east-1:123456789012:parameter/tailscale/id-token \
      --advertise-tags=tag:server

Updates tailscale/corp#28792

Signed-off-by: Andrew Dunham <andrew@tailscale.com>
2026-01-29 18:09:56 -05:00
Cameron Stokes aac12ba799 cmd/tailscale/cli: add json output option to switch --list (#18501)
* cmd/tailscale/cli: add json output option to `switch --list`

Closes #14783

Signed-off-by: Cameron Stokes <cameron@tailscale.com>
2026-01-27 13:42:04 -08:00
Will Norris 3ec5be3f51 all: remove AUTHORS file and references to it
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-23 15:49:45 -08:00
Danni Popova 6a6aa805d6 cmd,feature: add identity token auto generation for workload identity (#18373)
Adds the ability to detect what provider the client is running on and tries fetch the ID token to use with Workload Identity.

Updates https://github.com/tailscale/corp/issues/33316

Signed-off-by: Danni Popova <danni@tailscale.com>
2026-01-14 15:00:59 +00:00
Simon Law 3e45e5b420 feature/featuretags: make QR codes modular (#18358)
QR codes are used by `tailscale up --qr` to provide an easy way to
open a web-page without transcribing a difficult URI. However, there’s
no need for this feature if the client will never be called
interactively. So this PR adds the `ts_omit_qrcodes` build tag.

Updates #18182

Signed-off-by: Simon Law <sfllaw@tailscale.com>
2026-01-08 10:28:40 -08:00
Simon Law 522a6e385e cmd/tailscale/cli, util/qrcodes: format QR codes on Linux consoles (#18182)
Raw Linux consoles support UTF-8, but we cannot assume that all UTF-8
characters are available. The default Fixed and Terminus fonts don’t
contain half-block characters (`▀` and `▄`), but do contain the
full-block character (`█`).

Sometimes, Linux doesn’t have a framebuffer, so it falls back to VGA.
When this happens, the full-block character could be anywhere in
extended ASCII block, because we don’t know which code page is active.

This PR introduces `--qr-format=auto` which tries to heuristically
detect when Tailscale is printing to a raw Linux console, whether
UTF-8 is enabled, and which block characters have been mapped in the
console font.

If Unicode characters are unavailable, the new `--qr-format=ascii`
formatter uses `#` characters instead of full-block characters.

Fixes #12935

Signed-off-by: Simon Law <sfllaw@tailscale.com>
2026-01-07 18:12:06 -08:00
Naman Sood 480ee9fec0 ipn,cmd/tailscale/cli: set correct SNI name for TLS-terminated TCP Services (#17752)
Fixes #17749.

Signed-off-by: Naman Sood <mail@nsood.in>
2026-01-07 09:31:46 -05:00
Harry Harpham 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
Alex Chan 9c3a420e15 cmd/tailscale/cli: document why there's no --force-reauth on login
Change-Id: Ied799fefbbb4612c7ba57b8369a418b7704eebf8
Updates #18273
Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-12-22 14:58:30 +00:00
Tom Proctor bb3529fcd4 cmd/containerboot: support egress to Tailscale Service FQDNs (#17493)
Adds support for targeting FQDNs that are a Tailscale Service. Uses the
same method of searching for Services as the tailscale configure
kubeconfig command. This fixes using the tailscale.com/tailnet-fqdn
annotation for Kubernetes Service when the specified FQDN is a Tailscale
Service.

Fixes #16534

Change-Id: I422795de76dc83ae30e7e757bc4fbd8eec21cc64

Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com>
Signed-off-by: Becky Pauley <becky@tailscale.com>
2025-12-18 17:06:42 +00:00
Alex Chan 378ee20b9a cmd/tailscale/cli: stabilise the output of tailscale lock status --json
This patch stabilises the JSON output, and improves it in the following
ways:

* The AUM hash in Head uses the base32-encoded form of an AUM hash,
  consistent with how it's presented elsewhere
* TrustedKeys are the same format as the keys as `tailnet lock log --json`
* SigKind, Pubkey and KeyID are all presented consistently with other
  JSON output in NodeKeySignature
* FilteredPeers don't have a NodeKeySignature, because it will always
  be empty

For reference, here's the JSON output from the CLI prior to this change:

```json
{
  "Enabled": true,
  "Head": [
    196,
    69,
    63,
    243,
    213,
    133,
    123,
    46,
    183,
    203,
    143,
    34,
    184,
    85,
    80,
    1,
    221,
    92,
    49,
    213,
    93,
    106,
    5,
    206,
    176,
    250,
    58,
    165,
    155,
    136,
    11,
    13
  ],
  "PublicKey": "nlpub:0f99af5c02216193963ce9304bb4ca418846eddebe237f37a6de1c59097ed0b8",
  "NodeKey": "nodekey:8abfe98b38151748919f6e346ad16436201c3ecd453b01e9d6d3a38e1826000d",
  "NodeKeySigned": true,
  "NodeKeySignature": {
    "SigKind": 1,
    "Pubkey": "bnCKv+mLOBUXSJGfbjRq0WQ2IBw+zUU7AenW06OOGCYADQ==",
    "KeyID": "D5mvXAIhYZOWPOkwS7TKQYhG7d6+I383pt4cWQl+0Lg=",
    "Signature": "4DPW4v6MyLLwQ8AMDm27BVDGABjeC9gg1EfqRdKgzVXi/mJDwY9PTAoX0+0WTRs5SUksWjY0u1CLxq5xgjFGBA==",
    "Nested": null,
    "WrappingPubkey": "D5mvXAIhYZOWPOkwS7TKQYhG7d6+I383pt4cWQl+0Lg="
  },
  "TrustedKeys": [
    {
      "Key": "nlpub:0f99af5c02216193963ce9304bb4ca418846eddebe237f37a6de1c59097ed0b8",
      "Metadata": null,
      "Votes": 1
    },
    {
      "Key": "nlpub:de2254c040e728140d92bc967d51284e9daea103a28a97a215694c5bda2128b8",
      "Metadata": null,
      "Votes": 1
    }
  ],
  "VisiblePeers": [
    {
      "Name": "signing2.taila62b.unknown.c.ts.net.",
      "ID": 7525920332164264,
      "StableID": "nRX6TbAWm121DEVEL",
      "TailscaleIPs": [
        "100.110.67.20",
        "fd7a:115c:a1e0::9c01:4314"
      ],
      "NodeKey": "nodekey:10bf4a5c168051d700a29123cd81568377849da458abef4b328794ca9cae4313",
      "NodeKeySignature": {
        "SigKind": 1,
        "Pubkey": "bnAQv0pcFoBR1wCikSPNgVaDd4SdpFir70syh5TKnK5DEw==",
        "KeyID": "D5mvXAIhYZOWPOkwS7TKQYhG7d6+I383pt4cWQl+0Lg=",
        "Signature": "h9fhwHiNdkTqOGVQNdW6AVFoio6MFaFobPiK9ydywgmtYxcExJ38b76Tabdc56aNLxf8IfCaRw2VYPcQG2J/AA==",
        "Nested": null,
        "WrappingPubkey": "3iJUwEDnKBQNkryWfVEoTp2uoQOiipeiFWlMW9ohKLg="
      }
    }
  ],
  "FilteredPeers": [
    {
      "Name": "node3.taila62b.unknown.c.ts.net.",
      "ID": 5200614049042386,
      "StableID": "n3jAr7KNch11DEVEL",
      "TailscaleIPs": [
        "100.95.29.124",
        "fd7a:115c:a1e0::f901:1d7c"
      ],
      "NodeKey": "nodekey:454d2c8602c10574c5ec3a6790f159714802012b7b8bb8d2ab47d637f9df1d7b",
      "NodeKeySignature": {
        "SigKind": 0,
        "Pubkey": null,
        "KeyID": null,
        "Signature": null,
        "Nested": null,
        "WrappingPubkey": null
      }
    }
  ],
  "StateID": 16885615198276932820
}
```

Updates https://github.com/tailscale/corp/issues/22355
Updates https://github.com/tailscale/tailscale/issues/17619

Signed-off-by: Alex Chan <alexc@tailscale.com>

Change-Id: I65b58ff4520033e6b70fc3b1ba7fc91c1f70a960
2025-12-09 09:40:06 +00:00
Peter A. f4d34f38be cmd/tailscale,ipn: add Unix socket support for serve
Based on PR #16700 by @lox, adapted to current codebase.

Adds support for proxying HTTP requests to Unix domain sockets via
tailscale serve unix:/path/to/socket, enabling exposure of services
like Docker, containerd, PHP-FPM over Tailscale without TCP bridging.

The implementation includes reasonable protections against exposure of
tailscaled's own socket.

Adaptations from original PR:
- Use net.Dialer.DialContext instead of net.Dial for context propagation
- Use http.Transport with Protocols API (current h2c approach, not http2.Transport)
- Resolve conflicts with hasScheme variable in ExpandProxyTargetValue

Updates #9771

Signed-off-by: Peter A. <ink.splatters@pm.me>
Co-authored-by: Lachlan Donald <lachlan@ljd.cc>
2025-12-04 11:06:06 -08:00
Naasir 77dcdc223e cleanup: fix typos across multiple files
Does not affect code.

Updates #cleanup

Signed-off-by: Naasir <yoursdeveloper@protonmail.com>
2025-12-02 07:16:38 -08:00
Alex Chan bd12d8f12f cmd/tailscale/cli: soften the warning on --force-reauth for seamless
Thanks to seamless key renewal, you can now do a force-reauth without
losing your connection in all circumstances. We softened the interactive
warning (see #17262) so let's soften the help text as well.

Updates https://github.com/tailscale/corp/issues/32429

Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-12-01 14:37:06 +00:00
Jordan Whited 824027305a cmd/tailscale/cli,ipn,all: make peer relay server port a *uint16
In preparation for exposing its configuration via ipn.ConfigVAlpha,
change {Masked}Prefs.RelayServerPort from *int to *uint16. This takes a
defensive stance against invalid inputs at JSON decode time.

'tailscale set --relay-server-port' is currently the only input to this
pref, and has always sanitized input to fit within a uint16.

Updates tailscale/corp#34591

Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-11-25 19:40:17 -08:00
Jordan Whited 7426eca163 cmd/tailscale,feature/relayserver,ipn: add relay-server-static-endpoints set flag
Updates tailscale/corp#31489
Updates #17791

Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-11-24 16:37:15 -08:00
Harry Harpham 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
KevinLiang10 a0d059d74c cmd/tailscale/cli: allow remote target as service destination (#17607)
This commit enables user to set service backend to remote destinations, that can be a partial
URL or a full URL. The commit also prevents user to set remote destinations on linux system
when socket mark is not working. For user on any version of mac extension they can't serve a
service either. The socket mark usability is determined by a new local api.

Fixes tailscale/corp#24783

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>
2025-11-19 12:29:08 -05:00
Alex Chan 336df56f85 cmd/tailscale/cli: remove Latin abbreviations from CLI help text
Our style guide recommends avoiding Latin abbreviations in technical
documentation, which includes the CLI help text. This is causing linter
issues for the docs site, because this help text is copied into the docs.
See http://go/style-guide/kb/language-and-grammar/abbreviations#latin-abbreviations

Updates #cleanup

Change-Id: I980c28d996466f0503aaaa65127685f4af608039
Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-11-19 13:22:13 +00:00
James Tucker c09c95ef67 types/key,wgengine/magicsock,control/controlclient,ipn: add debug disco key rotation
Adds the ability to rotate discovery keys on running clients, needed for
testing upcoming disco key distribution changes.

Introduces key.DiscoKey, an atomic container for a disco private key,
public key, and the public key's ShortString, replacing the prior
separate atomic fields.

magicsock.Conn has a new RotateDiscoKey method, and access to this is
provided via localapi and a CLI debug command.

Note that this implementation is primarily for testing as it stands, and
regular use should likely introduce an additional mechanism that allows
the old key to be used for some time, to provide a seamless key rotation
rather than one that invalidates all sessions.

Updates tailscale/corp#34037

Signed-off-by: James Tucker <james@tailscale.com>
2025-11-18 12:16:15 -08:00
James 'zofrex' Sanderson a2e9dfacde cmd/tailscale/cli: warn if a simple up would change prefs (#17877)
Updates tailscale/corp#21570

Signed-off-by: James Sanderson <jsanderson@tailscale.com>
2025-11-18 07:53:42 +00:00
Brad Fitzpatrick f1cddc6ecf ipn{,/local},cmd/tailscale: add "sync" flag and pref to disable control map poll
For manual (human) testing, this lets the user disable control plane
map polls with "tailscale set --sync=false" (which survives restarts)
and "tailscale set --sync" to restore.

A high severity health warning is shown while this is active.

Updates #12639
Updates #17945

Change-Id: I83668fa5de3b5e5e25444df0815ec2a859153a6d
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-11-17 12:37:31 -08:00
Alex Chan 1723cb83ed ipn/ipnlocal: use an in-memory TKA store if FS is unavailable
This requires making the internals of LocalBackend a bit more generic,
and implementing the `tka.CompactableChonk` interface for `tka.Mem`.

Signed-off-by: Alex Chan <alexc@tailscale.com>

Updates https://github.com/tailscale/corp/issues/33599
2025-11-17 18:12:33 +00:00
Alex Chan 139c395d7d cmd/tailscale/cli: stabilise the output of tailscale lock log --json
This patch changes the behaviour of `tailscale lock log --json` to make
it more useful for users. It also introduces versioning of our JSON output.

## Changes to `tailscale lock log --json`

Previously this command would print the hash and base64-encoded bytes of
each AUM, and users would need their own CBOR decoder to interpret it in
a useful way:

```json
[
  {
    "Hash": [
      80,
      136,
      151,
      …
    ],
    "Change": "checkpoint",
    "Raw": "pAEFAvYFpQH2AopYIAkPN+8V3cJpkoC5ZY2+RI2Bcg2q5G7tRAQQd67W3YpnWCDPOo4KGeQBd8hdGsjoEQpSXyiPdlm+NXAlJ5dS1qEbFlggylNJDQM5ZQ2ULNsXxg2ZBFkPl/D93I1M56/rowU+UIlYIPZ/SxT9EA2Idy9kaCbsFzjX/s3Ms7584wWGbWd/f/QAWCBHYZzYiAPpQ+NXN+1Wn2fopQYk4yl7kNQcMXUKNAdt1lggcfjcuVACOH0J9pRNvYZQFOkbiBmLOW1hPKJsbC1D1GdYIKrJ38XMgpVMuTuBxM4YwoLmrK/RgXQw1uVEL3cywl3QWCA0FilVVv8uys8BNhS62cfNvCew1Pw5wIgSe3Prv8d8pFggQrwIt6ldYtyFPQcC5V18qrCnt7VpThACaz5RYzpx7RNYIKskOA7UoNiVtMkOrV2QoXv6EvDpbO26a01lVeh8UCeEA4KjAQECAQNYIORIdNHqSOzz1trIygnP5w3JWK2DtlY5NDIBbD7SKcjWowEBAgEDWCD27LpxiZNiA19k0QZhOWmJRvBdK2mz+dHu7rf0iGTPFwQb69Gt42fKNn0FGwRUiav/k6dDF4GiAVgg5Eh00epI7PPW2sjKCc/nDclYrYO2Vjk0MgFsPtIpyNYCWEDzIAooc+m45ay5PB/OB4AA9Fdki4KJq9Ll+PF6IJHYlOVhpTbc3E0KF7ODu1WURd0f7PXnW72dr89CSfGxIHAF"
  }
]
```

Now we print the AUM in an expanded form that can be easily read by scripts,
although we include the raw bytes for verification and auditing.

```json
{
  "SchemaVersion": "1",
  "Messages": [
    {
      "Hash": "KCEJPRKNSXJG2TPH3EHQRLJNLIIK2DV53FUNPADWA7BZJWBDRXZQ",
      "AUM": {
        "MessageKind": "checkpoint",
        "PrevAUMHash": null,
        "Key": null,
        "KeyID": null,
        "State": {
          …
        },
        "Votes": null,
        "Meta": null,
        "Signatures": [
          {
            "KeyID": "tlpub:e44874d1ea48ecf3d6dac8ca09cfe70dc958ad83b656393432016c3ed229c8d6",
            "Signature": "8yAKKHPpuOWsuTwfzgeAAPRXZIuCiavS5fjxeiCR2JTlYaU23NxNChezg7tVlEXdH+z151u9na/PQknxsSBwBQ=="
          }
        ]
      },
      "Raw": "pAEFAvYFpQH2AopYIAkPN-8V3cJpkoC5ZY2-RI2Bcg2q5G7tRAQQd67W3YpnWCDPOo4KGeQBd8hdGsjoEQpSXyiPdlm-NXAlJ5dS1qEbFlggylNJDQM5ZQ2ULNsXxg2ZBFkPl_D93I1M56_rowU-UIlYIPZ_SxT9EA2Idy9kaCbsFzjX_s3Ms7584wWGbWd_f_QAWCBHYZzYiAPpQ-NXN-1Wn2fopQYk4yl7kNQcMXUKNAdt1lggcfjcuVACOH0J9pRNvYZQFOkbiBmLOW1hPKJsbC1D1GdYIKrJ38XMgpVMuTuBxM4YwoLmrK_RgXQw1uVEL3cywl3QWCA0FilVVv8uys8BNhS62cfNvCew1Pw5wIgSe3Prv8d8pFggQrwIt6ldYtyFPQcC5V18qrCnt7VpThACaz5RYzpx7RNYIKskOA7UoNiVtMkOrV2QoXv6EvDpbO26a01lVeh8UCeEA4KjAQECAQNYIORIdNHqSOzz1trIygnP5w3JWK2DtlY5NDIBbD7SKcjWowEBAgEDWCD27LpxiZNiA19k0QZhOWmJRvBdK2mz-dHu7rf0iGTPFwQb69Gt42fKNn0FGwRUiav_k6dDF4GiAVgg5Eh00epI7PPW2sjKCc_nDclYrYO2Vjk0MgFsPtIpyNYCWEDzIAooc-m45ay5PB_OB4AA9Fdki4KJq9Ll-PF6IJHYlOVhpTbc3E0KF7ODu1WURd0f7PXnW72dr89CSfGxIHAF"
    }
  ]
}
```

This output was previously marked as unstable, and it wasn't very useful,
so changing it should be fine.

## Versioning our JSON output

This patch introduces a way to version our JSON output on the CLI, so we
can make backwards-incompatible changes in future without breaking existing
scripts or integrations.

You can run this command in two ways:

```
tailscale lock log --json
tailscale lock log --json=1
```

Passing an explicit version number allows you to pick a specific JSON schema.
If we ever want to change the schema, we increment the version number and
users must opt-in to the new output.

A bare `--json` flag will always return schema version 1, for compatibility
with existing scripts.

Updates https://github.com/tailscale/tailscale/issues/17613
Updates https://github.com/tailscale/corp/issues/23258

Signed-off-by: Alex Chan <alexc@tailscale.com>

Change-Id: I897f78521cc1a81651f5476228c0882d7b723606
2025-11-17 09:44:52 +00:00
Andrew Dunham 3a41c0c585 ipn/ipnlocal: add PROXY protocol support to Funnel/Serve
This adds the --proxy-protocol flag to 'tailscale serve' and
'tailscale funnel', which tells the Tailscale client to prepend a PROXY
protocol[1] header when making connections to the proxied-to backend.

I've verified that this works with our existing funnel servers without
additional work, since they pass along source address information via
PeerAPI already.

Updates #7747

[1]: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt

Change-Id: I647c24d319375c1b33e995555a541b7615d2d203
Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
2025-11-16 21:00:49 -05:00
Brad Fitzpatrick 653d0738f9 types/netmap: remove PrivateKey from NetworkMap
It's an unnecessary nuisance having it. We go out of our way to redact
it in so many places when we don't even need it there anyway.

Updates #12639

Change-Id: I5fc72e19e9cf36caeb42cf80ba430873f67167c3
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-11-16 15:32:51 -08:00
Xinyu Kuo 8444659ed8 cmd/tailscale/cli: fix panic in netcheck with mismatched DERP region IDs
Fixes #17564

Signed-off-by: Xinyu Kuo <gxylong@126.com>
2025-11-15 09:55:14 -08:00
Naman Sood ca9b68aafd cmd/tailscale/cli: remove service flag from funnel command (#17850)
Fixes #17849.

Signed-off-by: Naman Sood <mail@nsood.in>
2025-11-13 07:19:17 -05:00
Gesa Stupperich adee8b9180 cmd/tailscale/cli/serve_v2: improve validation error
Specify the app apability that failed the test, instead of the
entire comma-separated list.

Fixes #cleanup

Signed-off-by: Gesa Stupperich <gesa@tailscale.com>
2025-10-30 16:31:27 +00:00
Harry Harpham 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
Gesa Stupperich d2e4a20f26 ipn/ipnlocal/serve: error when PeerCaps serialisation fails
Also consolidates variable and header naming and amends the
CLI behavior
* multiple app-caps have to be specified as comma-separated
  list
* simple regex-based validation of app capability names is
  carried out during flag parsing

Signed-off-by: Gesa Stupperich <gesa@tailscale.com>
2025-10-28 10:33:24 +00:00
Gesa Stupperich d6fa899eba ipn/ipnlocal/serve: remove grant header truncation logic
Given that we filter based on the usercaps argument now, truncation
should not be necessary anymore.

Updates tailscale/corp/#28372

Signed-off-by: Gesa Stupperich <gesa@tailscale.com>
2025-10-28 10:33:24 +00:00
Gesa Stupperich 576aacd459 ipn/ipnlocal/serve: add grant headers
Updates tailscale/corp/#28372

Signed-off-by: Gesa Stupperich <gesa@tailscale.com>
2025-10-28 10:33:24 +00:00
srwareham f4e2720821 cmd/tailscale/cli: move JetKVM scripts to /userdata/init.d for persistence (#17610)
Updates #16524
Updates jetkvm/rv1106-system#34

Signed-off-by: srwareham <ebriouscoding@gmail.com>
2025-10-27 15:20:57 -07:00
Harry Harpham 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
Alex Chan c961d58091 cmd/tailscale: improve the error message for lock log with no lock
Previously, running `tailscale lock log` in a tailnet without Tailnet
Lock enabled would return a potentially confusing error:

    $ tailscale lock log
    2025/10/20 11:07:09 failed to connect to local Tailscale service; is Tailscale running?

It would return this error even if Tailscale was running.

This patch fixes the error to be:

    $ tailscale lock log
    Tailnet Lock is not enabled

Fixes #17586

Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-10-20 12:15:57 +01:00
Max Coulombe 6a73c0bdf5 cmd/tailscale/cli,feature: add support for identity federation (#17529)
Add new arguments to `tailscale up` so authkeys can be generated dynamically via identity federation.

Updates #9192

Signed-off-by: mcoulombe <max@tailscale.com>
2025-10-17 18:05:32 -04:00
Alex Chan 0ce88aa343 all: use a consistent capitalisation for "Tailnet Lock"
Updates https://github.com/tailscale/corp/issues/13108

Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-10-16 15:27:35 +01:00
Jordan Whited 743e5ac696 cmd/tailscale: surface relay-server-port set flag (#17528)
Fixes tailscale/corp#31186

Signed-off-by: Jordan Whited <jordan@tailscale.com>
2025-10-15 09:13:06 -07:00
Naman Sood f157f3288d cmd/tailscale/cli,ipn/conffile: add declarative config mode for Services (#17435)
This commit adds the subcommands `get-config` and `set-config` to Serve,
which can be used to read the current Tailscale Services configuration
in a standard syntax and provide a configuration to declaratively apply
with that same syntax.

Both commands must be provided with either `--service=svc:service` for
one service, or `--all` for all services. When writing a config,
`--set-config --all` will overwrite all existing Services configuration,
and `--set-config --service=svc:service` will overwrite all
configuration for that particular Service. Incremental changes are not
supported.

Fixes tailscale/corp#30983.

cmd/tailscale/cli: hide serve "get-config"/"set-config" commands for now

tailscale/corp#33152 tracks unhiding them when docs exist.

Signed-off-by: Naman Sood <mail@nsood.in>
2025-10-10 11:02:35 -04:00
Alex Chan b7fe1cea9f cmd/tailscale/cli: only print authURLs and device approval URLs once
This patch fixes several issues related to printing login and device
approval URLs, especially when `tailscale up` is interrupted:

1.  Only print a login URL that will cause `tailscale up` to complete.
    Don't print expired URLs or URLs from previous login attempts.

2.  Print the device approval URL if you run `tailscale up` after
    previously completing a login, but before approving the device.

3.  Use the correct control URL for device approval if you run a bare
    `tailscale up` after previously completing a login, but before
    approving the device.

4.  Don't print the device approval URL more than once (or at least,
    not consecutively).

Updates tailscale/corp#31476
Updates #17361

## How these fixes work

This patch went through a lot of trial and error, and there may still
be bugs! These notes capture the different scenarios and considerations
as we wrote it, which are also captured by integration tests.

1.  We were getting stale login URLs from the initial IPN state
    notification.

    When the IPN watcher was moved to before Start() in c011369, we
    mistakenly continued to request the initial state. This is only
    necessary if you start watching after you call Start(), because
    you may have missed some notifications.

    By getting the initial state before calling Start(), we'd get
    a stale login URL. If you clicked that URL, you could complete
    the login in the control server (if it wasn't expired), but your
    instance of `tailscale up` would hang, because it's listening for
    login updates from a different login URL.

    In this patch, we no longer request the initial state, and so we
    don't print a stale URL.

2.  Once you skip the initial state from IPN, the following sequence:

    *   Run `tailscale up`
    *   Log into a tailnet with device approval
    *   ^C after the device approval URL is printed, but without approving
    *   Run `tailscale up` again

    means that nothing would ever be printed.

    `tailscale up` would send tailscaled the pref `WantRunning: true`,
    but that was already the case so nothing changes. You never get any
    IPN notifications, and in particular you never get a state change to
    `NeedsMachineAuth`. This means we'd never print the device approval URL.

    In this patch, we add a hard-coded rule that if you're doing a simple up
    (which won't trigger any other IPN notifications) and you start in the
    `NeedsMachineAuth` state, we print the device approval message without
    waiting for an IPN notification.

3.  Consider the following sequence:

    *   Run `tailscale up --login-server=<custom server>`
    *   Log into a tailnet with device approval
    *   ^C after the device approval URL is printed, but without approving
    *   Run `tailscale up` again

    We'd print the device approval URL for the default control server,
    rather than the real control server, because we were using the `prefs`
    from the CLI arguments (which are all the defaults) rather than the
    `curPrefs` (which contain the custom login server).

    In this patch, we use the `prefs` if the user has specified any settings
    (and other code will ensure this is a complete set of settings) or
    `curPrefs` if it's a simple `tailscale up`.

4.  Consider the following sequence: you've logged in, but not completed
    device approval, and you run `down` and `up` in quick succession.

    *   `up`: sees state=NeedsMachineAuth
    *   `up`: sends `{wantRunning: true}`, prints out the device approval URL
    *   `down`: changes state to Stopped
    *   `up`: changes state to Starting
    *   tailscaled: changes state to NeedsMachineAuth
    *   `up`: gets an IPN notification with the state change, and prints
        a second device approval URL

    Either URL works, but this is annoying for the user.

    In this patch, we track whether the last printed URL was the device
    approval URL, and if so, we skip printing it a second time.

Signed-off-by: Alex Chan <alexc@tailscale.com>
2025-10-08 18:00:29 +01:00
Brad Fitzpatrick 541a4ed5b4 all: use buildfeatures consts in a few more places
Saves ~25 KB.

Updates #12614

Change-Id: I7b976e57819a0d2692824d779c8cc98033df0d30
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-06 10:48:55 -07:00
M. J. Fromberger 127a967207 appc,*: publish events for route updates and storage (#17392)
Add and wire up event publishers for these two event types in the AppConnector.
Nothing currently subscribes to them, so this is harmless. Subscribers for
these events will be added in a near-future commit.

As part of this, move the appc.RouteInfo type to the types/appctype package.
It does not contain any package-specific details from appc. Beside it, add
appctype.RouteUpdate to carry route update event state, likewise not specific
to appc.  Update all usage of the appc.* types throughout to use appctype.*
instead, and update depaware files to reflect these changes.

Add a Close method to the AppConnector to make sure the client gets cleaned up
when the connector is dropped (we re-create connectors).

Update the unit tests in the appc package to also check the events published
alongside calls to the RouteAdvertiser.

For now the tests still rely on the RouteAdvertiser for correctness; this is OK
for now as the two methods are always performed together.  In the near future,
we need to rework the tests so not require that, but that will require building
some more test fixtures that we can handle separately.

Updates #15160
Updates #17192

Change-Id: I184670ba2fb920e0d2cb2be7c6816259bca77afe
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-10-02 09:31:42 -07:00
Brad Fitzpatrick 1d93bdce20 control/controlclient: remove x/net/http2, use net/http
Saves 352 KB, removing one of our two HTTP/2 implementations linked
into the binary.

Fixes #17305
Updates #15015

Change-Id: I53a04b1f2687dca73c8541949465038b69aa6ade
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-02 08:25:14 -07:00
Brad Fitzpatrick 78af49dd1a control/ts2021: rename from internal/noiseconn in prep for controlclient split
A following change will split out the controlclient.NoiseClient type
out, away from the rest of the controlclient package which is
relatively dependency heavy.

A question was where to move it, and whether to make a new (a fifth!)
package in the ts2021 dependency chain.

@creachadair and I brainstormed and decided to merge
internal/noiseconn and controlclient.NoiseClient into one package,
with names ts2021.Conn and ts2021.Client.

For ease of reviewing the subsequent PR, this is the first step that
just renames the internal/noiseconn package to control/ts2021.

Updates #17305

Change-Id: Ib5ea162dc1d336c1d805bdd9548d1702dd6e1468
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-10-01 15:34:57 -07:00