Update
This commit is contained in:
1 parent
3530afb854
commit
6903fcff27
2146 files changed
+112256
-190703
No files matched your search
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// c2n (control-to-node) API types.
|
||||
|
||||
+56
-10
@@ -1,16 +1,21 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tailcfg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
||||
"tailscale.com/types/key"
|
||||
)
|
||||
|
||||
// DERPMap describes the set of DERP packet relay servers that are available.
|
||||
//
|
||||
// API maturity: this type is subject to minor changes over time, though
|
||||
// its general shape is stable.
|
||||
type DERPMap struct {
|
||||
// HomeParams, if non-nil, is a change in home parameters.
|
||||
//
|
||||
@@ -22,7 +27,7 @@ type DERPMap struct {
|
||||
// It's keyed by the DERPRegion.RegionID.
|
||||
//
|
||||
// The numbers are not necessarily contiguous.
|
||||
Regions map[int]*DERPRegion
|
||||
Regions map[DERPRegionID]*DERPRegion
|
||||
|
||||
// OmitDefaultRegions specifies to not use Tailscale's DERP servers, and only use those
|
||||
// specified in this DERPMap. If there are none set outside of the defaults, this is a noop.
|
||||
@@ -31,13 +36,13 @@ type DERPMap struct {
|
||||
OmitDefaultRegions bool `json:"omitDefaultRegions,omitempty"`
|
||||
}
|
||||
|
||||
// / RegionIDs returns the sorted region IDs.
|
||||
func (m *DERPMap) RegionIDs() []int {
|
||||
ret := make([]int, 0, len(m.Regions))
|
||||
// RegionIDs returns the sorted region IDs.
|
||||
func (m *DERPMap) RegionIDs() []DERPRegionID {
|
||||
ret := make([]DERPRegionID, 0, len(m.Regions))
|
||||
for rid := range m.Regions {
|
||||
ret = append(ret, rid)
|
||||
}
|
||||
sort.Ints(ret)
|
||||
slices.Sort(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -57,7 +62,48 @@ type DERPHomeParams struct {
|
||||
//
|
||||
// A nil map means no change from the previous value (if any); an empty
|
||||
// non-nil map can be sent to reset all scores back to 1.0.
|
||||
RegionScore map[int]float64 `json:",omitempty"`
|
||||
RegionScore map[DERPRegionID]float64 `json:",omitempty"`
|
||||
}
|
||||
|
||||
// DERPRegionID is a unique integer for a geographic region.
|
||||
//
|
||||
// It corresponds to the legacy derpN.tailscale.com hostnames used by older clients.
|
||||
// (Older clients will continue to resolve derpN.tailscale.com when contacting peers,
|
||||
// rather than use the server-provided DERPMap)
|
||||
//
|
||||
// It must be non-zero, positive, and guaranteed to fit in a JavaScript number.
|
||||
//
|
||||
// IDs in range 900-999 are reserved for end users to run their own DERP nodes.
|
||||
type DERPRegionID int64
|
||||
|
||||
// ParseDERPRegionID parses s and returns a [DERPRegionID].
|
||||
// It returns an error if s isn’t a valid region ID.
|
||||
func ParseDERPRegionID(s string) (DERPRegionID, error) {
|
||||
id, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rid := DERPRegionID(id)
|
||||
if !rid.IsValid() {
|
||||
return 0, fmt.Errorf("invalid region ID: %s", s)
|
||||
}
|
||||
return rid, nil
|
||||
}
|
||||
|
||||
// IsValid reports whether id is non-zero, positive, and fits in a JavaScript number.
|
||||
func (id DERPRegionID) IsValid() bool {
|
||||
const maxSafeJavaScriptInteger DERPRegionID = 1<<53 - 1 // Number.MAX_SAFE_INTEGER
|
||||
return id > 0 && id <= maxSafeJavaScriptInteger
|
||||
}
|
||||
|
||||
// Int64 returns the int64 representation of id.
|
||||
func (id DERPRegionID) Int64() int64 {
|
||||
return int64(id)
|
||||
}
|
||||
|
||||
// String implements the [fmt.Stringer] interface.
|
||||
func (id DERPRegionID) String() string {
|
||||
return strconv.FormatInt(int64(id), 10)
|
||||
}
|
||||
|
||||
// DERPRegion is a geographic region running DERP relay node(s).
|
||||
@@ -81,7 +127,7 @@ type DERPRegion struct {
|
||||
//
|
||||
// RegionIDs in range 900-999 are reserved for end users to run their
|
||||
// own DERP nodes.
|
||||
RegionID int
|
||||
RegionID DERPRegionID
|
||||
|
||||
// RegionCode is a short name for the region. It's usually a popular
|
||||
// city or airport code in the region: "nyc", "sf", "sin",
|
||||
@@ -147,7 +193,7 @@ type DERPNode struct {
|
||||
|
||||
// RegionID is the RegionID of the DERPRegion that this node
|
||||
// is running in.
|
||||
RegionID int
|
||||
RegionID DERPRegionID
|
||||
|
||||
// HostName is the DERP node's hostname.
|
||||
//
|
||||
|
||||
+450
@@ -0,0 +1,450 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package nodecap defines the types of capabilities granted to tailnet nodes.
|
||||
package nodecap
|
||||
|
||||
// Cap represents a capability granted to the self node
|
||||
// as listed in [tailscale.com/tailcfg/MapResponse.Node.Capabilities].
|
||||
//
|
||||
// It must be a URL like "https://tailscale.com/cap/file-sharing" or "tailscale.com/cap/webui",
|
||||
// or a well-known capability name like "funnel".
|
||||
// The latter is only allowed for Tailscale-defined capabilities.
|
||||
//
|
||||
// Unlike [tailscale.com/tailcfg/peercap.Cap],
|
||||
// Cap is not in context of a peer and is granted to the node itself.
|
||||
//
|
||||
// These are also referred to as "Node Attributes" in the ACL policy file.
|
||||
type Cap string
|
||||
|
||||
// Prefix is a prefix for [tailscale.com/tailcfg.NodeCapMap] keys that share a common namespace,
|
||||
// where each entry represents a distinct named instance (e.g. one per service).
|
||||
// The full key is formed by concatenating the prefix with the instance name.
|
||||
type Prefix string
|
||||
|
||||
// ToAttribute returns the full [Cap] key for the given value under this prefix,
|
||||
// of the form prefix+value.
|
||||
func (p Prefix) ToAttribute(value string) Cap {
|
||||
return Cap(string(p) + value)
|
||||
}
|
||||
|
||||
const (
|
||||
FileSharing Cap = "https://tailscale.com/cap/file-sharing"
|
||||
Admin Cap = "https://tailscale.com/cap/is-admin"
|
||||
Owner Cap = "https://tailscale.com/cap/is-owner"
|
||||
SSH Cap = "https://tailscale.com/cap/ssh" // feature enabled/available
|
||||
SSHRuleIn Cap = "https://tailscale.com/cap/ssh-rule-in" // some SSH rule reach this node
|
||||
DataPlaneAuditLogs Cap = "https://tailscale.com/cap/data-plane-audit-logs" // feature enabled
|
||||
Debug Cap = "https://tailscale.com/cap/debug" // exposes debug endpoints over the PeerAPI
|
||||
HTTPS Cap = "https"
|
||||
|
||||
// MacUIV2 makes the macOS GUI enable its v2 mode.
|
||||
MacUIV2 Cap = "https://tailscale.com/cap/mac-ui-v2"
|
||||
|
||||
// ServicesInDesktopClients enables services list/menu/section in desktop clients.
|
||||
// If this capability is not present, desktop clients should not show services.
|
||||
ServicesInDesktopClients Cap = "https://tailscale.com/cap/services-in-desktop-clients"
|
||||
|
||||
// BindToInterfaceByRoute changes how Darwin nodes create
|
||||
// sockets (in the net/netns package). See that package for more
|
||||
// details on the behaviour of this capability.
|
||||
BindToInterfaceByRoute Cap = "https://tailscale.com/cap/bind-to-interface-by-route"
|
||||
|
||||
// DisableAndroidBindToActiveNetwork disables binding sockets to the
|
||||
// currently active network on Android, which is enabled by default.
|
||||
// This allows the control plane to turn off the behavior if it causes
|
||||
// problems.
|
||||
DisableAndroidBindToActiveNetwork Cap = "disable-android-bind-to-active-network"
|
||||
|
||||
// DebugDisableAlternateDefaultRouteInterface changes how Darwin
|
||||
// nodes get the default interface. There is an optional hook (used by the
|
||||
// macOS and iOS clients) to override the default interface, this capability
|
||||
// disables that and uses the default behavior (of parsing the routing
|
||||
// table).
|
||||
DebugDisableAlternateDefaultRouteInterface Cap = "https://tailscale.com/cap/debug-disable-alternate-default-route-interface"
|
||||
|
||||
// DebugDisableBindConnToInterface disables the automatic binding
|
||||
// of connections to the default network interface on Darwin nodes.
|
||||
DebugDisableBindConnToInterface Cap = "https://tailscale.com/cap/debug-disable-bind-conn-to-interface"
|
||||
|
||||
// DebugDisableBindConnToInterface disables the automatic binding
|
||||
// of connections to the default network interface on Darwin nodes using network extensions
|
||||
DebugDisableBindConnToInterfaceAppleExt Cap = "https://tailscale.com/cap/debug-disable-bind-conn-to-interface-apple-ext"
|
||||
|
||||
// TailnetLock indicates the node may initialize tailnet lock.
|
||||
TailnetLock Cap = "https://tailscale.com/cap/tailnet-lock"
|
||||
|
||||
//// Funnel warning capabilities used for reporting errors to the user.
|
||||
|
||||
// WarnFunnelNoInvite indicates whether Funnel is enabled for the tailnet.
|
||||
// This cap is no longer used 2023-08-09 onwards.
|
||||
WarnFunnelNoInvite Cap = "https://tailscale.com/cap/warn-funnel-no-invite"
|
||||
|
||||
// WarnFunnelNoHTTPS indicates HTTPS has not been enabled for the tailnet.
|
||||
// This cap is no longer used 2023-08-09 onwards.
|
||||
WarnFunnelNoHTTPS Cap = "https://tailscale.com/cap/warn-funnel-no-https"
|
||||
|
||||
//// Debug logging capabilities
|
||||
|
||||
// DebugTSDNSResolution enables verbose debug logging for DNS
|
||||
// resolution for Tailscale-controlled domains (the control server, log
|
||||
// server, DERP servers, etc.)
|
||||
DebugTSDNSResolution Cap = "https://tailscale.com/cap/debug-ts-dns-resolution"
|
||||
|
||||
// FunnelPorts specifies the ports that the Funnel is available on.
|
||||
// The ports are specified as a comma-separated list of port numbers or port
|
||||
// ranges (e.g. "80,443,8080-8090") in the ports query parameter.
|
||||
// e.g. https://tailscale.com/cap/funnel-ports?ports=80,443,8080-8090
|
||||
FunnelPorts Cap = "https://tailscale.com/cap/funnel-ports"
|
||||
|
||||
// OnlyTCP443 specifies that the client should not attempt to generate
|
||||
// any outbound traffic that isn't TCP on port 443 (HTTPS). This is used for
|
||||
// clients in restricted environments where only HTTPS traffic is allowed
|
||||
// other types of traffic trips outbound firewall alarms. This thus implies
|
||||
// all traffic is over DERP.
|
||||
OnlyTCP443 Cap = "only-tcp-443"
|
||||
|
||||
// Funnel grants the ability for a node to host ingress traffic.
|
||||
Funnel Cap = "funnel"
|
||||
// SSHAggregator grants the ability for a node to collect SSH sessions.
|
||||
SSHAggregator Cap = "ssh-aggregator"
|
||||
|
||||
// DebugForceBackgroundSTUN forces a node to always do background
|
||||
// STUN queries regardless of inactivity.
|
||||
DebugForceBackgroundSTUN Cap = "debug-always-stun"
|
||||
|
||||
// DebugDisableWGTrim disables the lazy WireGuard configuration,
|
||||
// always giving WireGuard the full netmap, even for idle peers.
|
||||
DebugDisableWGTrim Cap = "debug-no-wg-trim"
|
||||
|
||||
// DisableSubnetsIfPAC controls whether subnet routers should be
|
||||
// disabled if WPAD is present on the network.
|
||||
DisableSubnetsIfPAC Cap = "debug-disable-subnets-if-pac"
|
||||
|
||||
// DisableUPnP makes the client not perform a UPnP portmapping.
|
||||
// By default, we want to enable it to see if it works on more clients.
|
||||
//
|
||||
// If UPnP catastrophically fails for people, this should be set kill
|
||||
// new attempts at UPnP connections.
|
||||
DisableUPnP Cap = "debug-disable-upnp"
|
||||
|
||||
// DisableDeltaUpdates makes the client not process updates via the
|
||||
// delta update mechanism and should instead treat all netmap changes as
|
||||
// "full" ones as tailscaled did in 1.48.x and earlier.
|
||||
DisableDeltaUpdates Cap = "disable-delta-updates"
|
||||
|
||||
// RandomizeClientPort makes magicsock UDP bind to
|
||||
// :0 to get a random local port, ignoring any configured
|
||||
// fixed port.
|
||||
RandomizeClientPort Cap = "randomize-client-port"
|
||||
|
||||
// SilentDisco makes the client suppress disco heartbeats to its
|
||||
// peers.
|
||||
SilentDisco Cap = "silent-disco"
|
||||
|
||||
// OneCGNATEnable makes the client prefer one big CGNAT /10 route
|
||||
// rather than a /32 per peer. At most one of this or
|
||||
// [OneCGNATDisable] may be set; if neither are, it's automatic.
|
||||
OneCGNATEnable Cap = "one-cgnat?v=true"
|
||||
|
||||
// OneCGNATDisable makes the client prefer a /32 route per peer
|
||||
// rather than one big /10 CGNAT route. At most one of this or
|
||||
// [OneCGNATEnable] may be set; if neither are, it's automatic.
|
||||
OneCGNATDisable Cap = "one-cgnat?v=false"
|
||||
|
||||
// PeerMTUEnable makes the client do path MTU discovery to its
|
||||
// peers. If it isn't set, it defaults to the client default.
|
||||
PeerMTUEnable Cap = "peer-mtu-enable"
|
||||
|
||||
// DNSForwarderDisableTCPRetries disables retrying truncated
|
||||
// DNS queries over TCP if the response is truncated.
|
||||
DNSForwarderDisableTCPRetries Cap = "dns-forwarder-disable-tcp-retries"
|
||||
|
||||
// LinuxMustUseIPTables forces Linux clients to use iptables for
|
||||
// netfilter management.
|
||||
// This cannot be set simultaneously with [LinuxMustUseNfTables].
|
||||
LinuxMustUseIPTables Cap = "linux-netfilter?v=iptables"
|
||||
|
||||
// LinuxMustUseNfTables forces Linux clients to use nftables for
|
||||
// netfilter management.
|
||||
// This cannot be set simultaneously with [LinuxMustUseIPTables].
|
||||
LinuxMustUseNfTables Cap = "linux-netfilter?v=nftables"
|
||||
|
||||
// ProbeUDPLifetime makes the client probe UDP path lifetime at the
|
||||
// tail end of an active direct connection in magicsock.
|
||||
ProbeUDPLifetime Cap = "probe-udp-lifetime"
|
||||
|
||||
// TaildriveShare enables sharing via Taildrive.
|
||||
TaildriveShare Cap = "drive:share"
|
||||
|
||||
// TaildriveAccess enables accessing shares via Taildrive.
|
||||
TaildriveAccess Cap = "drive:access"
|
||||
|
||||
// SuggestExitNode is applied to each exit node which the control plane has determined
|
||||
// is a recommended exit node.
|
||||
SuggestExitNode Cap = "suggest-exit-node"
|
||||
|
||||
// DisableWebClient disables using the web client.
|
||||
DisableWebClient Cap = "disable-web-client"
|
||||
|
||||
// LogExitFlows enables exit node destinations in network flow logs.
|
||||
LogExitFlows Cap = "log-exit-flows"
|
||||
|
||||
// AutoExitNode permits the automatic exit nodes feature.
|
||||
AutoExitNode Cap = "auto-exit-node"
|
||||
|
||||
// StoreAppCRoutes configures the node to store app connector routes persistently.
|
||||
StoreAppCRoutes Cap = "store-appc-routes"
|
||||
|
||||
// SuggestExitNodeUI allows the currently suggested exit node to appear in the client GUI.
|
||||
SuggestExitNodeUI Cap = "suggest-exit-node-ui"
|
||||
|
||||
// UserDialUseRoutes makes UserDial use either the peer dialer or the system dialer,
|
||||
// depending on the destination address and the configured routes. When present, it also makes
|
||||
// the DNS forwarder use UserDial instead of SystemDial when dialing resolvers.
|
||||
UserDialUseRoutes Cap = "user-dial-routes"
|
||||
|
||||
// SSHBehaviorV1 forces SSH to use the V1 behavior (no su, run SFTP in-process)
|
||||
// Added 2024-05-29 in Tailscale version 1.68.
|
||||
SSHBehaviorV1 Cap = "ssh-behavior-v1"
|
||||
|
||||
// SSHBehaviorV2 forces SSH to use the V2 behavior (use su, run SFTP in child process).
|
||||
// This overrides [SSHBehaviorV1] if set.
|
||||
// See forceV1Behavior in ssh/tailssh/incubator.go for distinction between
|
||||
// V1 and V2 behavior.
|
||||
// Added 2024-08-06 in Tailscale version 1.72.
|
||||
SSHBehaviorV2 Cap = "ssh-behavior-v2"
|
||||
|
||||
// DisableSplitDNSWhenNoCustomResolvers indicates that the node's
|
||||
// DNS manager should not adopt a split DNS configuration even though the
|
||||
// Config of the resolver only contains routes that do not specify custom
|
||||
// resolver(s), hence all DNS queries can be safely sent to the upstream
|
||||
// DNS resolver and the node's DNS forwarder doesn't need to handle all
|
||||
// DNS traffic.
|
||||
// This is for now (2024-06-06) an iOS-specific battery life optimization,
|
||||
// and this node attribute allows us to disable the optimization remotely
|
||||
// if needed.
|
||||
DisableSplitDNSWhenNoCustomResolvers Cap = "disable-split-dns-when-no-custom-resolvers"
|
||||
|
||||
// ScopeQuad100OnMacOS lets sandboxed macOS scope quad-100 for simple DNS
|
||||
// configs, so public queries can use the OS resolver (including DoH).
|
||||
// Custom split resolvers or unrouted forward/PTR records still require
|
||||
// quad-100 as primary. Without this attribute, quad-100 stays primary.
|
||||
// Has no effect on other platforms. See tailscale/corp#45534 and
|
||||
// tailscale/corp#48693.
|
||||
ScopeQuad100OnMacOS Cap = "scope-quad100-macos"
|
||||
|
||||
// DisableLocalDNSOverrideViaNRPT indicates that the node's DNS manager should not
|
||||
// create a default (catch-all) Windows NRPT rule when "Override local DNS" is enabled.
|
||||
// Without this rule, Windows 8.1 and newer devices issue parallel DNS requests to DNS servers
|
||||
// associated with all network adapters, even when "Override local DNS" is enabled and/or
|
||||
// a Mullvad exit node is being used, resulting in DNS leaks.
|
||||
// We began creating this rule on 2024-06-14, and this node attribute
|
||||
// allows us to disable the new behavior remotely if needed.
|
||||
DisableLocalDNSOverrideViaNRPT Cap = "disable-local-dns-override-via-nrpt"
|
||||
|
||||
// DisableMagicSockCryptoRouting disables the use of the
|
||||
// magicsock cryptorouting hook. See tailscale/corp#20732.
|
||||
//
|
||||
// Deprecated: [DisableMagicSockCryptoRouting] is deprecated as of
|
||||
// [tailscale.com/tailcfg.CapabilityVersion] 124,
|
||||
// CryptoRouting is now mandatory. See tailscale/corp#31083.
|
||||
DisableMagicSockCryptoRouting Cap = "disable-magicsock-crypto-routing"
|
||||
|
||||
// DisableCaptivePortalDetection instructs the client to not perform captive portal detection
|
||||
// automatically when the network state changes.
|
||||
DisableCaptivePortalDetection Cap = "disable-captive-portal-detection"
|
||||
|
||||
// DisableSkipStatusQueue is set when the node should disable skipping
|
||||
// of queued netmap.NetworkMap between the controlclient and LocalBackend.
|
||||
// See tailscale/tailscale#14768.
|
||||
DisableSkipStatusQueue Cap = "disable-skip-status-queue"
|
||||
|
||||
// SSHEnvironmentVariables enables logic for handling environment variables sent
|
||||
// via SendEnv in the SSH server and applying them to the SSH session.
|
||||
SSHEnvironmentVariables Cap = "ssh-env-vars"
|
||||
|
||||
// ServiceHost indicates the VIP Services for which the client is
|
||||
// approved to act as a service host, and which IP addresses are assigned
|
||||
// to those VIP Services. Any VIP Services that the client is not
|
||||
// advertising can be ignored.
|
||||
// Each value of this key in [NodeCapMap] is of type [ServiceIPMappings].
|
||||
// If multiple values of this key exist, they should be merged in sequence
|
||||
// (replace conflicting keys).
|
||||
ServiceHost Cap = "service-host"
|
||||
|
||||
// MaxKeyDuration represents the MaxKeyDuration setting on the
|
||||
// tailnet. The value of this key in [NodeCapMap] will be only one entry of
|
||||
// type float64 representing the duration in seconds. This cap will be
|
||||
// omitted if the tailnet's MaxKeyDuration is the default.
|
||||
MaxKeyDuration Cap = "tailnet.maxKeyDuration"
|
||||
|
||||
// NativeIPV4 contains the IPV4 address of the node in its
|
||||
// native tailnet. This is currently only sent to Hello, in its
|
||||
// peer node list.
|
||||
NativeIPV4 Cap = "native-ipv4"
|
||||
|
||||
// DisableRelayServer prevents the node from acting as an underlay
|
||||
// UDP relay server. There are no expected values for this key; the key
|
||||
// only needs to be present in [NodeCapMap] to take effect.
|
||||
DisableRelayServer Cap = "disable-relay-server"
|
||||
|
||||
// DisableRelayClient prevents the node from both allocating UDP
|
||||
// relay server endpoints itself, and from using endpoints allocated by
|
||||
// its peers. This attribute can be added to the node dynamically; if added
|
||||
// while the node is already running, the node will be unable to allocate
|
||||
// endpoints after it next updates its network map, and will be immediately
|
||||
// unable to use new paths via a UDP relay server. Setting this attribute
|
||||
// dynamically does not remove any existing paths, including paths that
|
||||
// traverse a UDP relay server. There are no expected values for this key
|
||||
// in [NodeCapMap]; the key only needs to be present in [NodeCapMap] to
|
||||
// take effect.
|
||||
DisableRelayClient Cap = "disable-relay-client"
|
||||
|
||||
// MagicDNSPeerAAAA is a capability that tells the node's MagicDNS
|
||||
// server to answer AAAA queries about its peers. See tailscale/tailscale#1152.
|
||||
MagicDNSPeerAAAA Cap = "magicdns-aaaa"
|
||||
|
||||
// DNSSubdomainResolve, when set on Self or a Peer node, indicates
|
||||
// that the subdomains of that node's MagicDNS name should resolve to the
|
||||
// same IP addresses as the node itself.
|
||||
// For example, if node "myserver.tailnet.ts.net" has this capability,
|
||||
// then "anything.myserver.tailnet.ts.net" will resolve to myserver's IPs.
|
||||
DNSSubdomainResolve Cap = "dns-subdomain-resolve"
|
||||
|
||||
// TrafficSteering configures the node to use the traffic
|
||||
// steering subsystem for via routes. See tailscale/corp#29966.
|
||||
TrafficSteering Cap = "traffic-steering"
|
||||
|
||||
// TailnetDisplayName is an optional alternate name for the tailnet
|
||||
// to be displayed to the user.
|
||||
// If empty or absent, a default is used.
|
||||
// If this value is present and set by a user this will only include letters,
|
||||
// numbers, apostrophe, spaces, and hyphens. This may not be true for the default.
|
||||
// Values can look like "foo.com" or "Foo's Test Tailnet - Staging".
|
||||
TailnetDisplayName Cap = "tailnet-display-name"
|
||||
|
||||
// ClientSideReachability configures the node to determine
|
||||
// reachability itself when choosing connectors. When absent, the
|
||||
// default behavior is to trust the control plane when it claims that a
|
||||
// node is no longer online, but that is not a reliable signal.
|
||||
//
|
||||
// It is temporary and will be ignored once its behaviour becomes the default.
|
||||
ClientSideReachability Cap = "client-side-reachability"
|
||||
|
||||
// ClientSideReachabilityRouteCheck configures the node to use
|
||||
// the routecheck subsystem to determine reachability when choosing
|
||||
// connectors. This relies on [ClientSideReachability] being set.
|
||||
// See tailscale/tailscale#17367.
|
||||
//
|
||||
// It is temporary and will be ignored once its behaviour becomes the default.
|
||||
ClientSideReachabilityRouteCheck Cap = "client-side-reachability-routecheck"
|
||||
|
||||
// DefaultAutoUpdate advertises the default node auto-update setting
|
||||
// for this tailnet. The node is free to opt-in or out locally regardless of
|
||||
// this value. Once this has been set and stored in the client, future
|
||||
// changes from the control plane are ignored.
|
||||
//
|
||||
// The value of the key in [NodeCapMap] is a JSON boolean.
|
||||
DefaultAutoUpdate Cap = "default-auto-update"
|
||||
|
||||
// DisableHostsFileUpdates indicates that the node's DNS manager should
|
||||
// not create hosts file entries when it normally would, such as when we're not
|
||||
// the primary resolver on Windows or when the host is domain-joined and its
|
||||
// primary domain takes precedence over MagicDNS. As of 2026-02-12, it is only
|
||||
// used on Windows.
|
||||
DisableHostsFileUpdates Cap = "disable-hosts-file-updates"
|
||||
|
||||
// ForceRegisterMagicDNSIPv4Only forces the client to only register
|
||||
// its MagicDNS IPv4 address with systemd/etc, and not both its IPv4 and IPv6 addresses.
|
||||
// See https://github.com/tailscale/tailscale/issues/15404.
|
||||
// TODO(bradfitz): remove this a few releases after 2026-02-16.
|
||||
ForceRegisterMagicDNSIPv4Only Cap = "force-register-magicdns-ipv4-only"
|
||||
|
||||
// CacheNetworkMaps instructs the node to persistently cache network
|
||||
// maps and use them to establish peer connectivity on start, if doing so is
|
||||
// supported by the client and storage is available. When this attribute is
|
||||
// absent (or removed), a node that supports netmap caching will ignore and
|
||||
// discard existing cached maps, and will not store any.
|
||||
CacheNetworkMaps Cap = "cache-network-maps"
|
||||
|
||||
// DisableCacheNetworkMaps indicates that the node should not cache
|
||||
// network maps (as per [CacheNetworkMaps]) when it normally would.
|
||||
// This attribute exists to allow the policy document to override the default.
|
||||
// When set, it takes precedence over [CacheNetworkMaps].
|
||||
DisableCacheNetworkMaps Cap = "disable-cache-network-maps"
|
||||
|
||||
// DisableLinuxCGNATDropRule tells Linux clients to not insert a
|
||||
// blanket firewall DROP rule for inbound traffic from the CGNAT IP range
|
||||
// that does not originate from the Tailscale network interface.
|
||||
// This enables access to off-tailnet endpoints within that IP range.
|
||||
DisableLinuxCGNATDropRule Cap = "disable-linux-cgnat-drop-rule"
|
||||
|
||||
// EmitRuntimeMetrics enables emission of [runtime/metrics] as
|
||||
// [tailscale.com/util/clientmetric]'s.
|
||||
EmitRuntimeMetrics Cap = "emit-runtime-metrics"
|
||||
|
||||
// ConnReject enables the node's aggregated connection-rejection diagnostic
|
||||
// buffers and the debug-rejects LocalAPI and GET /debug/rejects c2n endpoints.
|
||||
ConnReject Cap = "debug-conn-reject"
|
||||
|
||||
// DisableUDPGRO disables UDP GRO (UDP_GRO socket option on Linux)
|
||||
// on the magicsock UDP socket. It exists so control can mitigate kernel
|
||||
// regressions that cause throughput or correctness issues with UDP GRO on
|
||||
// specific OS/kernel versions, without requiring a client release. See
|
||||
// https://github.com/tailscale/tailscale/issues/19777 for example.
|
||||
// Currently only consulted on Linux; may apply to other platforms as they
|
||||
// gain UDP GRO support.
|
||||
DisableUDPGRO Cap = "disable-udp-gro"
|
||||
|
||||
// DisableUDPGSO disables UDP GSO (UDP_SEGMENT socket option on
|
||||
// Linux) on the magicsock UDP socket. It exists so control can mitigate
|
||||
// kernel regressions that cause throughput or correctness issues with UDP
|
||||
// GSO on specific OS/kernel versions, without requiring a client release.
|
||||
// See https://github.com/tailscale/tailscale/issues/19777 for example.
|
||||
// Currently only consulted on Linux; may apply to other platforms as they
|
||||
// gain UDP GSO support.
|
||||
DisableUDPGSO Cap = "disable-udp-gso"
|
||||
|
||||
// DisableTUNUDPGRO disables UDP GRO on the Tailscale TUN device.
|
||||
// It exists so control can mitigate kernel regressions that cause
|
||||
// throughput or correctness issues with TUN UDP GRO on specific OS/kernel
|
||||
// versions, without requiring a client release. See
|
||||
// https://github.com/tailscale/tailscale/issues/13041 for example.
|
||||
// Currently only consulted on Linux; may apply to other platforms as they
|
||||
// gain TUN UDP GRO support.
|
||||
DisableTUNUDPGRO Cap = "disable-tun-udp-gro"
|
||||
|
||||
// DisableTUNTCPGRO disables TCP GRO on the Tailscale TUN device.
|
||||
// It exists so control can mitigate kernel regressions that cause
|
||||
// throughput or correctness issues with TUN TCP GRO on specific OS/kernel
|
||||
// versions, without requiring a client release. See
|
||||
// https://github.com/tailscale/tailscale/issues/13041 for example.
|
||||
// Currently only consulted on Linux; may apply to other platforms as they
|
||||
// gain TUN TCP GRO support.
|
||||
DisableTUNTCPGRO Cap = "disable-tun-tcp-gro"
|
||||
|
||||
// NeverGSOEqualTail enables a sentinel-tail workaround in the
|
||||
// underlay UDP packet TX path on Linux. Applies to magicsock and peer relay
|
||||
// UDP sockets. The workaround avoids emitting UDP GSO batches whose
|
||||
// fragments are all equal in length, at a small payload and packet overhead
|
||||
// cost. It exists so control can mitigate kernel regressions that mangle
|
||||
// UDP headers or checksums for equal-length GSO batches, without requiring
|
||||
// a client release. See https://github.com/tailscale/tailscale/issues/19777.
|
||||
NeverGSOEqualTail Cap = "never-gso-equal-tail"
|
||||
|
||||
// Conn25Connector specifies which conn25 apps a peer is a connector for.
|
||||
// Presence of this field means that this client may try to use the peer as
|
||||
// a connector for the domains specified in the named app's configuration.
|
||||
Conn25Connector Cap = "conn25-connector-apps"
|
||||
)
|
||||
|
||||
const (
|
||||
// ServicesPrefix is the prefix for per-service [NodeCapMap]
|
||||
// entries describing Services visible (accessible) to this node.
|
||||
// Each value under such a key is of type [ServiceDetails].
|
||||
// The suffix after the prefix is an opaque server-chosen identifier;
|
||||
// consumers must use [ServiceDetails.Name] as the canonical service name
|
||||
// rather than parsing it from the map key.
|
||||
ServicesPrefix Prefix = "services/"
|
||||
)
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package peercap defines the capabilities that can be granted to peer nodes.
|
||||
package peercap
|
||||
|
||||
// Cap represents a capability granted to a peer by a [tailscale.com/tailcfg.FilterRule]
|
||||
// when the peer communicates with the node that has this rule.
|
||||
// Its meaning is application-defined.
|
||||
//
|
||||
// It must be a URL like "https://tailscale.com/cap/file-send"
|
||||
// or "tailscale.com/cap/webui".
|
||||
type Cap string
|
||||
|
||||
// Prefix is a prefix for [tailscale.com/tailcfg.PeerCapMap] keys that share a
|
||||
// common namespace, where each entry represents a distinct named instance (e.g.
|
||||
// one per App definition). The full key is formed by concatenating the prefix
|
||||
// with the instance name.
|
||||
type Prefix string
|
||||
|
||||
// ToAttribute returns the full [Cap] key for the given value under this prefix,
|
||||
// of the form prefix+value.
|
||||
func (p Prefix) ToAttribute(value string) Cap {
|
||||
return Cap(string(p) + value)
|
||||
}
|
||||
|
||||
const (
|
||||
// FileSharingTarget grants the current node the ability to send
|
||||
// files to the peer which has this capability.
|
||||
FileSharingTarget Cap = "https://tailscale.com/cap/file-sharing-target"
|
||||
// FileSharingSend grants the ability to receive files from a
|
||||
// node that's owned by a different user.
|
||||
FileSharingSend Cap = "https://tailscale.com/cap/file-send"
|
||||
// DebugPeer grants the ability for a peer to read this node's
|
||||
// goroutines, metrics, magicsock internal state, etc.
|
||||
DebugPeer Cap = "https://tailscale.com/cap/debug-peer"
|
||||
// WakeOnLAN grants the ability to send a Wake-On-LAN packet.
|
||||
WakeOnLAN Cap = "https://tailscale.com/cap/wake-on-lan"
|
||||
// Ingress grants the ability for a peer to send ingress traffic.
|
||||
Ingress Cap = "https://tailscale.com/cap/ingress"
|
||||
// WebUI grants the ability for a peer to edit features from the
|
||||
// device Web UI.
|
||||
WebUI Cap = "tailscale.com/cap/webui"
|
||||
// Taildrive grants the ability for a peer to access Taildrive
|
||||
// shares.
|
||||
Taildrive Cap = "tailscale.com/cap/drive"
|
||||
// TaildriveSharer indicates that a peer has the ability to
|
||||
// share folders with us.
|
||||
TaildriveSharer Cap = "tailscale.com/cap/drive-sharer"
|
||||
|
||||
// Kubernetes grants a peer Kubernetes-specific
|
||||
// capabilities, such as the ability to impersonate specific Tailscale
|
||||
// user groups as Kubernetes user groups. This capability is read by
|
||||
// peers that are Tailscale Kubernetes operator instances.
|
||||
Kubernetes Cap = "tailscale.com/cap/kubernetes"
|
||||
|
||||
// Relay grants the ability for a peer to allocate relay
|
||||
// endpoints.
|
||||
Relay Cap = "tailscale.com/cap/relay"
|
||||
// RelayTarget grants the current node the ability to allocate
|
||||
// relay endpoints to the peer which has this capability.
|
||||
RelayTarget Cap = "tailscale.com/cap/relay-target"
|
||||
|
||||
// TsIDP grants a peer tsidp-specific
|
||||
// capabilities, such as the ability to add user groups to the OIDC
|
||||
// claim
|
||||
TsIDP Cap = "tailscale.com/cap/tsidp"
|
||||
)
|
||||
|
||||
const (
|
||||
// Conn25Prefix is the prefix for per-app [Cap] names that grant a peer
|
||||
// access to an app provided by a conn25 app connector.
|
||||
// Actual capabilities look like "tailscale.com/cap/conn25/example" for
|
||||
// an app named "example".
|
||||
// Each value under such a key is a [tailscale.com/tailcfg.ProtoPortRange].
|
||||
// If multiple values are present, the union of all protocol/port
|
||||
// combinations described shall be permitted.
|
||||
Conn25Prefix Prefix = "tailscale.com/cap/conn25/"
|
||||
)
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tailcfg
|
||||
@@ -119,7 +119,7 @@ func parseProtoPortRange(ipProtoPort string) (*ProtoPortRange, error) {
|
||||
}
|
||||
|
||||
// ParseHostPortRange parses hostport as HOST:PORTS where HOST is
|
||||
// returned unchanged and PORTS is is either "*" or PORTLOW-PORTHIGH ranges.
|
||||
// returned unchanged and PORTS is either "*" or PORTLOW-PORTHIGH ranges.
|
||||
func ParseHostPortRange(hostport string) (host string, ports PortRange, err error) {
|
||||
hostport = strings.ToLower(hostport)
|
||||
colon := strings.LastIndexByte(hostport, ':')
|
||||
|
||||
+431
-383
File diff suppressed because it is too large.
Load diff
+40
-24
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Code generated by tailscale.com/cmd/cloner; DO NOT EDIT.
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"tailscale.com/tailcfg/nodecap"
|
||||
"tailscale.com/types/dnstype"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/opt"
|
||||
"tailscale.com/types/ptr"
|
||||
"tailscale.com/types/structs"
|
||||
"tailscale.com/types/tkatype"
|
||||
)
|
||||
@@ -53,23 +53,23 @@ func (src *Node) Clone() *Node {
|
||||
dst.Tags = append(src.Tags[:0:0], src.Tags...)
|
||||
dst.PrimaryRoutes = append(src.PrimaryRoutes[:0:0], src.PrimaryRoutes...)
|
||||
if dst.LastSeen != nil {
|
||||
dst.LastSeen = ptr.To(*src.LastSeen)
|
||||
dst.LastSeen = new(*src.LastSeen)
|
||||
}
|
||||
if dst.Online != nil {
|
||||
dst.Online = ptr.To(*src.Online)
|
||||
dst.Online = new(*src.Online)
|
||||
}
|
||||
dst.Capabilities = append(src.Capabilities[:0:0], src.Capabilities...)
|
||||
if dst.CapMap != nil {
|
||||
dst.CapMap = map[NodeCapability][]RawMessage{}
|
||||
dst.CapMap = map[nodecap.Cap][]RawMessage{}
|
||||
for k := range src.CapMap {
|
||||
dst.CapMap[k] = append([]RawMessage{}, src.CapMap[k]...)
|
||||
}
|
||||
}
|
||||
if dst.SelfNodeV4MasqAddrForThisPeer != nil {
|
||||
dst.SelfNodeV4MasqAddrForThisPeer = ptr.To(*src.SelfNodeV4MasqAddrForThisPeer)
|
||||
dst.SelfNodeV4MasqAddrForThisPeer = new(*src.SelfNodeV4MasqAddrForThisPeer)
|
||||
}
|
||||
if dst.SelfNodeV6MasqAddrForThisPeer != nil {
|
||||
dst.SelfNodeV6MasqAddrForThisPeer = ptr.To(*src.SelfNodeV6MasqAddrForThisPeer)
|
||||
dst.SelfNodeV6MasqAddrForThisPeer = new(*src.SelfNodeV6MasqAddrForThisPeer)
|
||||
}
|
||||
if src.ExitNodeDNSResolvers != nil {
|
||||
dst.ExitNodeDNSResolvers = make([]*dnstype.Resolver, len(src.ExitNodeDNSResolvers))
|
||||
@@ -100,7 +100,7 @@ var _NodeCloneNeedsRegeneration = Node(struct {
|
||||
AllowedIPs []netip.Prefix
|
||||
Endpoints []netip.AddrPort
|
||||
LegacyDERPString string
|
||||
HomeDERP int
|
||||
HomeDERP DERPRegionID
|
||||
Hostinfo HostinfoView
|
||||
Created time.Time
|
||||
Cap CapabilityVersion
|
||||
@@ -109,7 +109,7 @@ var _NodeCloneNeedsRegeneration = Node(struct {
|
||||
LastSeen *time.Time
|
||||
Online *bool
|
||||
MachineAuthorized bool
|
||||
Capabilities []NodeCapability
|
||||
Capabilities []nodecap.Cap
|
||||
CapMap NodeCapMap
|
||||
UnsignedPeerAPIOnly bool
|
||||
ComputedName string
|
||||
@@ -122,6 +122,7 @@ var _NodeCloneNeedsRegeneration = Node(struct {
|
||||
IsWireGuardOnly bool
|
||||
IsJailed bool
|
||||
ExitNodeDNSResolvers []*dnstype.Resolver
|
||||
StableTailnetID StableTailnetID
|
||||
}{})
|
||||
|
||||
// Clone makes a deep copy of Hostinfo.
|
||||
@@ -139,10 +140,10 @@ func (src *Hostinfo) Clone() *Hostinfo {
|
||||
dst.NetInfo = src.NetInfo.Clone()
|
||||
dst.SSH_HostKeys = append(src.SSH_HostKeys[:0:0], src.SSH_HostKeys...)
|
||||
if dst.Location != nil {
|
||||
dst.Location = ptr.To(*src.Location)
|
||||
dst.Location = new(*src.Location)
|
||||
}
|
||||
if dst.TPM != nil {
|
||||
dst.TPM = ptr.To(*src.TPM)
|
||||
dst.TPM = new(*src.TPM)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
@@ -168,6 +169,7 @@ var _HostinfoCloneNeedsRegeneration = Hostinfo(struct {
|
||||
ShieldsUp bool
|
||||
ShareeNode bool
|
||||
NoLogsNoSupport bool
|
||||
RemoteConfig bool
|
||||
WireIngress bool
|
||||
IngressEnabled bool
|
||||
AllowsUpdate bool
|
||||
@@ -186,6 +188,7 @@ var _HostinfoCloneNeedsRegeneration = Hostinfo(struct {
|
||||
UserspaceRouter opt.Bool
|
||||
AppConnector opt.Bool
|
||||
ServicesHash string
|
||||
PeerRelay bool
|
||||
ExitNodeID StableNodeID
|
||||
Location *Location
|
||||
TPM *TPMInfo
|
||||
@@ -215,7 +218,7 @@ var _NetInfoCloneNeedsRegeneration = NetInfo(struct {
|
||||
UPnP opt.Bool
|
||||
PMP opt.Bool
|
||||
PCP opt.Bool
|
||||
PreferredDERP int
|
||||
PreferredDERP DERPRegionID
|
||||
LinkType string
|
||||
DERPLatency map[string]float64
|
||||
FirewallMode string
|
||||
@@ -262,8 +265,19 @@ func (src *DNSConfig) Clone() *DNSConfig {
|
||||
}
|
||||
if dst.Routes != nil {
|
||||
dst.Routes = map[string][]*dnstype.Resolver{}
|
||||
for k := range src.Routes {
|
||||
dst.Routes[k] = append([]*dnstype.Resolver{}, src.Routes[k]...)
|
||||
for k, sv := range src.Routes {
|
||||
if sv == nil {
|
||||
dst.Routes[k] = nil
|
||||
continue
|
||||
}
|
||||
dst.Routes[k] = make([]*dnstype.Resolver, len(sv))
|
||||
for i := range sv {
|
||||
if sv[i] == nil {
|
||||
dst.Routes[k][i] = nil
|
||||
} else {
|
||||
dst.Routes[k][i] = sv[i].Clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if src.FallbackResolvers != nil {
|
||||
@@ -330,7 +344,7 @@ func (src *RegisterResponseAuth) Clone() *RegisterResponseAuth {
|
||||
dst := new(RegisterResponseAuth)
|
||||
*dst = *src
|
||||
if dst.Oauth2Token != nil {
|
||||
dst.Oauth2Token = ptr.To(*src.Oauth2Token)
|
||||
dst.Oauth2Token = new(*src.Oauth2Token)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
@@ -354,7 +368,7 @@ func (src *RegisterRequest) Clone() *RegisterRequest {
|
||||
dst.Hostinfo = src.Hostinfo.Clone()
|
||||
dst.NodeKeySignature = append(src.NodeKeySignature[:0:0], src.NodeKeySignature...)
|
||||
if dst.Timestamp != nil {
|
||||
dst.Timestamp = ptr.To(*src.Timestamp)
|
||||
dst.Timestamp = new(*src.Timestamp)
|
||||
}
|
||||
dst.DeviceCert = append(src.DeviceCert[:0:0], src.DeviceCert...)
|
||||
dst.Signature = append(src.Signature[:0:0], src.Signature...)
|
||||
@@ -395,7 +409,7 @@ func (src *DERPHomeParams) Clone() *DERPHomeParams {
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _DERPHomeParamsCloneNeedsRegeneration = DERPHomeParams(struct {
|
||||
RegionScore map[int]float64
|
||||
RegionScore map[DERPRegionID]float64
|
||||
}{})
|
||||
|
||||
// Clone makes a deep copy of DERPRegion.
|
||||
@@ -412,7 +426,7 @@ func (src *DERPRegion) Clone() *DERPRegion {
|
||||
if src.Nodes[i] == nil {
|
||||
dst.Nodes[i] = nil
|
||||
} else {
|
||||
dst.Nodes[i] = ptr.To(*src.Nodes[i])
|
||||
dst.Nodes[i] = new(*src.Nodes[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -421,7 +435,7 @@ func (src *DERPRegion) Clone() *DERPRegion {
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _DERPRegionCloneNeedsRegeneration = DERPRegion(struct {
|
||||
RegionID int
|
||||
RegionID DERPRegionID
|
||||
RegionCode string
|
||||
RegionName string
|
||||
Latitude float64
|
||||
@@ -441,7 +455,7 @@ func (src *DERPMap) Clone() *DERPMap {
|
||||
*dst = *src
|
||||
dst.HomeParams = src.HomeParams.Clone()
|
||||
if dst.Regions != nil {
|
||||
dst.Regions = map[int]*DERPRegion{}
|
||||
dst.Regions = map[DERPRegionID]*DERPRegion{}
|
||||
for k, v := range src.Regions {
|
||||
if v == nil {
|
||||
dst.Regions[k] = nil
|
||||
@@ -456,7 +470,7 @@ func (src *DERPMap) Clone() *DERPMap {
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _DERPMapCloneNeedsRegeneration = DERPMap(struct {
|
||||
HomeParams *DERPHomeParams
|
||||
Regions map[int]*DERPRegion
|
||||
Regions map[DERPRegionID]*DERPRegion
|
||||
OmitDefaultRegions bool
|
||||
}{})
|
||||
|
||||
@@ -474,7 +488,7 @@ func (src *DERPNode) Clone() *DERPNode {
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _DERPNodeCloneNeedsRegeneration = DERPNode(struct {
|
||||
Name string
|
||||
RegionID int
|
||||
RegionID DERPRegionID
|
||||
HostName string
|
||||
CertName string
|
||||
IPv4 string
|
||||
@@ -496,7 +510,7 @@ func (src *SSHRule) Clone() *SSHRule {
|
||||
dst := new(SSHRule)
|
||||
*dst = *src
|
||||
if dst.RuleExpires != nil {
|
||||
dst.RuleExpires = ptr.To(*src.RuleExpires)
|
||||
dst.RuleExpires = new(*src.RuleExpires)
|
||||
}
|
||||
if src.Principals != nil {
|
||||
dst.Principals = make([]*SSHPrincipal, len(src.Principals))
|
||||
@@ -533,7 +547,7 @@ func (src *SSHAction) Clone() *SSHAction {
|
||||
*dst = *src
|
||||
dst.Recorders = append(src.Recorders[:0:0], src.Recorders...)
|
||||
if dst.OnRecordingFailure != nil {
|
||||
dst.OnRecordingFailure = ptr.To(*src.OnRecordingFailure)
|
||||
dst.OnRecordingFailure = new(*src.OnRecordingFailure)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
@@ -620,6 +634,7 @@ func (src *UserProfile) Clone() *UserProfile {
|
||||
}
|
||||
dst := new(UserProfile)
|
||||
*dst = *src
|
||||
dst.Groups = append(src.Groups[:0:0], src.Groups...)
|
||||
return dst
|
||||
}
|
||||
|
||||
@@ -629,6 +644,7 @@ var _UserProfileCloneNeedsRegeneration = UserProfile(struct {
|
||||
LoginName string
|
||||
DisplayName string
|
||||
ProfilePicURL string
|
||||
Groups []string
|
||||
}{})
|
||||
|
||||
// Clone makes a deep copy of VIPService.
|
||||
|
||||
+61
-23
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Code generated by tailscale/cmd/viewer; DO NOT EDIT.
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
jsonv2 "github.com/go-json-experiment/json"
|
||||
"github.com/go-json-experiment/json/jsontext"
|
||||
"tailscale.com/tailcfg/nodecap"
|
||||
"tailscale.com/types/dnstype"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/opt"
|
||||
@@ -230,7 +231,7 @@ func (v NodeView) LegacyDERPString() string { return v.ж.LegacyDERPString }
|
||||
//
|
||||
// HomeDERP may be zero if not (yet) known, but ideally always be non-zero
|
||||
// for magicsock connectivity to function normally.
|
||||
func (v NodeView) HomeDERP() int { return v.ж.HomeDERP }
|
||||
func (v NodeView) HomeDERP() DERPRegionID { return v.ж.HomeDERP }
|
||||
func (v NodeView) Hostinfo() HostinfoView { return v.ж.Hostinfo }
|
||||
func (v NodeView) Created() time.Time { return v.ж.Created }
|
||||
|
||||
@@ -277,7 +278,7 @@ func (v NodeView) MachineAuthorized() bool { return v.ж.MachineAuthorized }
|
||||
// "https://tailscale.com/cap/file-sharing"
|
||||
//
|
||||
// Deprecated: use CapMap instead. See https://github.com/tailscale/tailscale/issues/11508
|
||||
func (v NodeView) Capabilities() views.Slice[NodeCapability] { return views.SliceOf(v.ж.Capabilities) }
|
||||
func (v NodeView) Capabilities() views.Slice[nodecap.Cap] { return views.SliceOf(v.ж.Capabilities) }
|
||||
|
||||
// CapMap is a map of capabilities to their optional argument/data values.
|
||||
//
|
||||
@@ -288,7 +289,7 @@ func (v NodeView) Capabilities() views.Slice[NodeCapability] { return views.Slic
|
||||
// represented by the Capabilities field, but can now be represented by
|
||||
// CapMap with an empty value.
|
||||
//
|
||||
// See NodeCapability for more information on keys.
|
||||
// See [nodecap.Cap] for more information on keys.
|
||||
//
|
||||
// Metadata about nodes can be transmitted in 3 ways:
|
||||
// 1. MapResponse.Node.CapMap describes attributes that affect behavior for
|
||||
@@ -299,7 +300,7 @@ func (v NodeView) Capabilities() views.Slice[NodeCapability] { return views.Slic
|
||||
// 3. MapResponse.Peers[].CapMap describes attributes regarding a peer node,
|
||||
// such as which features the peer supports or if that peer is preferred
|
||||
// for a particular task vs other peers that could also be chosen.
|
||||
func (v NodeView) CapMap() views.MapSlice[NodeCapability, RawMessage] {
|
||||
func (v NodeView) CapMap() views.MapSlice[nodecap.Cap, RawMessage] {
|
||||
return views.MapSliceOf(v.ж.CapMap)
|
||||
}
|
||||
|
||||
@@ -375,7 +376,14 @@ func (v NodeView) IsJailed() bool { return v.ж.IsJailed }
|
||||
func (v NodeView) ExitNodeDNSResolvers() views.SliceView[*dnstype.Resolver, dnstype.ResolverView] {
|
||||
return views.SliceOfViews[*dnstype.Resolver, dnstype.ResolverView](v.ж.ExitNodeDNSResolvers)
|
||||
}
|
||||
func (v NodeView) Equal(v2 NodeView) bool { return v.ж.Equal(v2.ж) }
|
||||
|
||||
// StableTailnetID is the identifier of the tailnet this node is a
|
||||
// member of.
|
||||
//
|
||||
// Control only populates this for the self node in a MapResponse
|
||||
// (MapResponse.Node); it is empty for peers.
|
||||
func (v NodeView) StableTailnetID() StableTailnetID { return v.ж.StableTailnetID }
|
||||
func (v NodeView) Equal(v2 NodeView) bool { return v.ж.Equal(v2.ж) }
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _NodeViewNeedsRegeneration = Node(struct {
|
||||
@@ -393,7 +401,7 @@ var _NodeViewNeedsRegeneration = Node(struct {
|
||||
AllowedIPs []netip.Prefix
|
||||
Endpoints []netip.AddrPort
|
||||
LegacyDERPString string
|
||||
HomeDERP int
|
||||
HomeDERP DERPRegionID
|
||||
Hostinfo HostinfoView
|
||||
Created time.Time
|
||||
Cap CapabilityVersion
|
||||
@@ -402,7 +410,7 @@ var _NodeViewNeedsRegeneration = Node(struct {
|
||||
LastSeen *time.Time
|
||||
Online *bool
|
||||
MachineAuthorized bool
|
||||
Capabilities []NodeCapability
|
||||
Capabilities []nodecap.Cap
|
||||
CapMap NodeCapMap
|
||||
UnsignedPeerAPIOnly bool
|
||||
ComputedName string
|
||||
@@ -415,6 +423,7 @@ var _NodeViewNeedsRegeneration = Node(struct {
|
||||
IsWireGuardOnly bool
|
||||
IsJailed bool
|
||||
ExitNodeDNSResolvers []*dnstype.Resolver
|
||||
StableTailnetID StableTailnetID
|
||||
}{})
|
||||
|
||||
// View returns a read-only view of Hostinfo.
|
||||
@@ -550,6 +559,14 @@ func (v HostinfoView) ShareeNode() bool { return v.ж.ShareeNode }
|
||||
// indicates that the user has opted out of sending logs and support
|
||||
func (v HostinfoView) NoLogsNoSupport() bool { return v.ж.NoLogsNoSupport }
|
||||
|
||||
// RemoteConfig is whether the node has both linked
|
||||
// feature/remoteconfig into its binary and enabled
|
||||
// Prefs.RemoteConfig: it has delegated full remote management of
|
||||
// its prefs and LocalAPI to the tailnet admin via the
|
||||
// /remoteapi/localapi/* c2n endpoint. See feature/remoteconfig for
|
||||
// the trust model.
|
||||
func (v HostinfoView) RemoteConfig() bool { return v.ж.RemoteConfig }
|
||||
|
||||
// WireIngress indicates that the node would like to be wired up server-side
|
||||
// (DNS, etc) to be able to use Tailscale Funnel, even if it's not currently
|
||||
// enabled. For example, the user might only use it for intermittent
|
||||
@@ -562,7 +579,10 @@ func (v HostinfoView) WireIngress() bool { return v.ж.WireIngress }
|
||||
// if the node has any funnel endpoint enabled
|
||||
func (v HostinfoView) IngressEnabled() bool { return v.ж.IngressEnabled }
|
||||
|
||||
// indicates that the node has opted-in to admin-console-drive remote updates
|
||||
// AllowsUpdate reports that the node has opted in to
|
||||
// admin-console-driven remote updates and that the running binary
|
||||
// includes client update support (the feature/clientupdate package,
|
||||
// which tsnet apps don't include).
|
||||
func (v HostinfoView) AllowsUpdate() bool { return v.ж.AllowsUpdate }
|
||||
|
||||
// the current host's machine type (uname -m)
|
||||
@@ -606,6 +626,9 @@ func (v HostinfoView) AppConnector() opt.Bool { return v.ж.AppConnector }
|
||||
// opaque hash of the most recent list of tailnet services, change in hash indicates config should be fetched via c2n
|
||||
func (v HostinfoView) ServicesHash() string { return v.ж.ServicesHash }
|
||||
|
||||
// if the client is willing to relay traffic for other peers
|
||||
func (v HostinfoView) PeerRelay() bool { return v.ж.PeerRelay }
|
||||
|
||||
// the client’s selected exit node, empty when unselected.
|
||||
func (v HostinfoView) ExitNodeID() StableNodeID { return v.ж.ExitNodeID }
|
||||
|
||||
@@ -646,6 +669,7 @@ var _HostinfoViewNeedsRegeneration = Hostinfo(struct {
|
||||
ShieldsUp bool
|
||||
ShareeNode bool
|
||||
NoLogsNoSupport bool
|
||||
RemoteConfig bool
|
||||
WireIngress bool
|
||||
IngressEnabled bool
|
||||
AllowsUpdate bool
|
||||
@@ -664,6 +688,7 @@ var _HostinfoViewNeedsRegeneration = Hostinfo(struct {
|
||||
UserspaceRouter opt.Bool
|
||||
AppConnector opt.Bool
|
||||
ServicesHash string
|
||||
PeerRelay bool
|
||||
ExitNodeID StableNodeID
|
||||
Location *Location
|
||||
TPM *TPMInfo
|
||||
@@ -773,12 +798,12 @@ func (v NetInfoView) PCP() opt.Bool { return v.ж.PCP }
|
||||
|
||||
// PreferredDERP is this node's preferred (home) DERP region ID.
|
||||
// This is where the node expects to be contacted to begin a
|
||||
// peer-to-peer connection. The node might be be temporarily
|
||||
// peer-to-peer connection. The node might be temporarily
|
||||
// connected to multiple DERP servers (to speak to other nodes
|
||||
// that are located elsewhere) but PreferredDERP is the region ID
|
||||
// that the node subscribes to traffic at.
|
||||
// Zero means disconnected or unknown.
|
||||
func (v NetInfoView) PreferredDERP() int { return v.ж.PreferredDERP }
|
||||
func (v NetInfoView) PreferredDERP() DERPRegionID { return v.ж.PreferredDERP }
|
||||
|
||||
// LinkType is the current link type, if known.
|
||||
func (v NetInfoView) LinkType() string { return v.ж.LinkType }
|
||||
@@ -813,7 +838,7 @@ var _NetInfoViewNeedsRegeneration = NetInfo(struct {
|
||||
UPnP opt.Bool
|
||||
PMP opt.Bool
|
||||
PCP opt.Bool
|
||||
PreferredDERP int
|
||||
PreferredDERP DERPRegionID
|
||||
LinkType string
|
||||
DERPLatency map[string]float64
|
||||
FirewallMode string
|
||||
@@ -1345,7 +1370,7 @@ func (v RegisterRequestView) Hostinfo() HostinfoView { return v.ж.Hostinfo.View
|
||||
func (v RegisterRequestView) Ephemeral() bool { return v.ж.Ephemeral }
|
||||
|
||||
// NodeKeySignature is the node's own node-key signature, re-signed
|
||||
// for its new node key using its network-lock key.
|
||||
// for its new node key using its tailnet-lock key.
|
||||
//
|
||||
// This field is set when the client retries registration after learning
|
||||
// its NodeKeySignature (which is in need of rotation).
|
||||
@@ -1483,13 +1508,13 @@ func (v *DERPHomeParamsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
|
||||
//
|
||||
// A nil map means no change from the previous value (if any); an empty
|
||||
// non-nil map can be sent to reset all scores back to 1.0.
|
||||
func (v DERPHomeParamsView) RegionScore() views.Map[int, float64] {
|
||||
func (v DERPHomeParamsView) RegionScore() views.Map[DERPRegionID, float64] {
|
||||
return views.MapOf(v.ж.RegionScore)
|
||||
}
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _DERPHomeParamsViewNeedsRegeneration = DERPHomeParams(struct {
|
||||
RegionScore map[int]float64
|
||||
RegionScore map[DERPRegionID]float64
|
||||
}{})
|
||||
|
||||
// View returns a read-only view of DERPRegion.
|
||||
@@ -1571,7 +1596,7 @@ func (v *DERPRegionView) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
|
||||
//
|
||||
// RegionIDs in range 900-999 are reserved for end users to run their
|
||||
// own DERP nodes.
|
||||
func (v DERPRegionView) RegionID() int { return v.ж.RegionID }
|
||||
func (v DERPRegionView) RegionID() DERPRegionID { return v.ж.RegionID }
|
||||
|
||||
// RegionCode is a short name for the region. It's usually a popular
|
||||
// city or airport code in the region: "nyc", "sf", "sin",
|
||||
@@ -1630,7 +1655,7 @@ func (v DERPRegionView) Nodes() views.SliceView[*DERPNode, DERPNodeView] {
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _DERPRegionViewNeedsRegeneration = DERPRegion(struct {
|
||||
RegionID int
|
||||
RegionID DERPRegionID
|
||||
RegionCode string
|
||||
RegionName string
|
||||
Latitude float64
|
||||
@@ -1717,7 +1742,7 @@ func (v DERPMapView) HomeParams() DERPHomeParamsView { return v.ж.HomeParams.Vi
|
||||
// It's keyed by the DERPRegion.RegionID.
|
||||
//
|
||||
// The numbers are not necessarily contiguous.
|
||||
func (v DERPMapView) Regions() views.MapFn[int, *DERPRegion, DERPRegionView] {
|
||||
func (v DERPMapView) Regions() views.MapFn[DERPRegionID, *DERPRegion, DERPRegionView] {
|
||||
return views.MapFnOf(v.ж.Regions, func(t *DERPRegion) DERPRegionView {
|
||||
return t.View()
|
||||
})
|
||||
@@ -1732,7 +1757,7 @@ func (v DERPMapView) OmitDefaultRegions() bool { return v.ж.OmitDefaultRegions
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _DERPMapViewNeedsRegeneration = DERPMap(struct {
|
||||
HomeParams *DERPHomeParams
|
||||
Regions map[int]*DERPRegion
|
||||
Regions map[DERPRegionID]*DERPRegion
|
||||
OmitDefaultRegions bool
|
||||
}{})
|
||||
|
||||
@@ -1811,7 +1836,7 @@ func (v DERPNodeView) Name() string { return v.ж.Name }
|
||||
|
||||
// RegionID is the RegionID of the DERPRegion that this node
|
||||
// is running in.
|
||||
func (v DERPNodeView) RegionID() int { return v.ж.RegionID }
|
||||
func (v DERPNodeView) RegionID() DERPRegionID { return v.ж.RegionID }
|
||||
|
||||
// HostName is the DERP node's hostname.
|
||||
//
|
||||
@@ -1875,7 +1900,7 @@ func (v DERPNodeView) CanPort80() bool { return v.ж.CanPort80 }
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _DERPNodeViewNeedsRegeneration = DERPNode(struct {
|
||||
Name string
|
||||
RegionID int
|
||||
RegionID DERPRegionID
|
||||
HostName string
|
||||
CertName string
|
||||
IPv4 string
|
||||
@@ -2091,6 +2116,11 @@ func (v SSHActionView) Accept() bool { return v.ж.Accept }
|
||||
|
||||
// SessionDuration, if non-zero, is how long the session can stay open
|
||||
// before being forcefully terminated.
|
||||
// It is encoded as an int64 of nanoseconds (Go's time.Duration
|
||||
// wire format for encoding/json v1). It must not use a jsonv2
|
||||
// format tag; the mere presence of one makes Go 1.27's
|
||||
// encoding/json fail to decode the struct. See
|
||||
// https://github.com/tailscale/tailscale/issues/20528.
|
||||
func (v SSHActionView) SessionDuration() time.Duration { return v.ж.SessionDuration }
|
||||
|
||||
// AllowAgentForwarding, if true, allows accepted connections to forward
|
||||
@@ -2501,8 +2531,15 @@ func (v UserProfileView) ID() UserID { return v.ж.ID }
|
||||
func (v UserProfileView) LoginName() string { return v.ж.LoginName }
|
||||
|
||||
// "Alice Smith"
|
||||
func (v UserProfileView) DisplayName() string { return v.ж.DisplayName }
|
||||
func (v UserProfileView) ProfilePicURL() string { return v.ж.ProfilePicURL }
|
||||
func (v UserProfileView) DisplayName() string { return v.ж.DisplayName }
|
||||
func (v UserProfileView) ProfilePicURL() string { return v.ж.ProfilePicURL }
|
||||
|
||||
// Groups is a subset of SCIM groups (e.g. "engineering@example.com")
|
||||
// or group names in the tailnet policy document (e.g. "group:eng")
|
||||
// that contain this user and that the coordination server was
|
||||
// configured to report to this node.
|
||||
// The list is always sorted when loaded from storage.
|
||||
func (v UserProfileView) Groups() views.Slice[string] { return views.SliceOf(v.ж.Groups) }
|
||||
func (v UserProfileView) Equal(v2 UserProfileView) bool { return v.ж.Equal(v2.ж) }
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
@@ -2511,6 +2548,7 @@ var _UserProfileViewNeedsRegeneration = UserProfile(struct {
|
||||
LoginName string
|
||||
DisplayName string
|
||||
ProfilePicURL string
|
||||
Groups []string
|
||||
}{})
|
||||
|
||||
// View returns a read-only view of VIPService.
|
||||
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tailcfg
|
||||
@@ -36,7 +36,7 @@ type TKASignInfo struct {
|
||||
// a NodeKeySignature (NKS), which rotates the node key.
|
||||
//
|
||||
// This is necessary so the node can rotate its node-key without
|
||||
// talking to a node which holds a trusted network-lock key.
|
||||
// talking to a node which holds a trusted tailnet-lock key.
|
||||
// It does this by nesting the original NKS in a 'rotation' NKS,
|
||||
// which it then signs with the key corresponding to RotationPubkey.
|
||||
//
|
||||
@@ -111,7 +111,7 @@ type TKABootstrapRequest struct {
|
||||
NodeKey key.NodePublic
|
||||
|
||||
// Head represents the node's head AUMHash (tka.Authority.Head), if
|
||||
// network lock is enabled.
|
||||
// tailnet lock is enabled.
|
||||
Head string
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ type TKASyncSendResponse struct {
|
||||
Head string
|
||||
}
|
||||
|
||||
// TKADisableRequest disables network-lock across the tailnet using the
|
||||
// TKADisableRequest disables tailnet-lock across the tailnet using the
|
||||
// provided disablement secret.
|
||||
//
|
||||
// This is the request schema for a /tka/disable noise RPC.
|
||||
|
||||
Reference in new issue
Block a user