pub struct Node<'a> {Show 33 fields
pub id: NodeId,
pub stable_id: StableNodeId<'a>,
pub name: Cow<'a, str>,
pub user: UserId,
pub sharer: UserId,
pub key: NodePublicKey,
pub key_expiry: Option<DateTime<Utc>>,
pub key_signature: MarshaledSignature<'a>,
pub machine: Option<MachinePublicKey>,
pub disco_key: Option<DiscoPublicKey>,
pub addresses: Vec<IpNet>,
pub allowed_ips: Option<Vec<IpNet>>,
pub endpoints: Vec<SocketAddr>,
pub legacy_derp_string: Option<RegionId>,
pub home_derp: Option<RegionId>,
pub host_info: HostInfo<'a>,
pub created: DateTime<Utc>,
pub cap: CapabilityVersion,
pub tags: Option<Vec<&'a str>>,
pub primary_routes: Vec<IpNet>,
pub last_seen: Option<DateTime<Utc>>,
pub online: Option<bool>,
pub machine_authorized: bool,
pub capabilities: Vec<NodeCap<'a>>,
pub cap_map: Map<'a>,
pub unsigned_peer_api_only: bool,
pub data_plane_audit_log_id: &'a str,
pub expired: bool,
pub self_node_v4_masq_addr_for_this_peer: Option<IpAddr>,
pub self_node_v6_masq_addr_for_this_peer: Option<IpAddr>,
pub is_wireguard_only: bool,
pub is_jailed: bool,
pub exit_node_dns_resolvers: Vec<DnsResolver<'a>>,
}Expand description
A Tailscale device in a Tailnet.
The struct-level #[serde_with::apply] block makes every Vec/map field tolerate a wire
null (Go marshals empty omitempty slices/maps as null; see
crate::util::null_to_default). Applying it at the struct level — rather than annotating each
field — means any Vec/map field added later is covered automatically, closing the recurring
“forgot a field” gap that broke decoding against IPv6-off control planes. Option<Vec<…>> fields
(e.g. allowed_ips, tags) are written as Option<Vec<…>>, matched by none of the rules below
(the apply macro matches the type exactly as written), so they keep their null → None
semantics untouched. The path-qualified ts_nodecapability::Map rule is required because the
cap_map field is written with that full path — a bare Map token would not match it.
Fields§
§id: NodeIdA unique integer ID for the Tailscale node.
stable_id: StableNodeId<'a>A string representation of the Tailscale node’s Node::id field.
name: Cow<'a, str>The fully-qualified domain name (FQDN) of this node, as well as the MagicDNS name for the node. Ends with a trailing dot, e.g. “host.tail-scale.ts.net.”
user: UserIdUnique ID of the User who created the node.
If ACL tags are in use for the node, this field doesn’t reflect the ACL identity that the node is running as.
Unique ID of the user who shared this node, if non-zero and different from Node::user.
key: NodePublicKeyIf populated, the public key of the Tailscale node’s NodeKeyPair.
key_expiry: Option<DateTime<Utc>>The date and time that the Tailscale node’s NodeKeyPair will expire.
key_signature: MarshaledSignature<'a>If populated, a signature of the Tailnet Key Authority (TKA) key authorizing the Tailscale node to join the Tailnet.
machine: Option<MachinePublicKey>If populated, the public key of the Tailscale node’s MachineKeyPair.
disco_key: Option<DiscoPublicKey>If populated, the public key of the Tailscale node’s DiscoKeyPair.
addresses: Vec<IpNet>The IP addresses (CIDR prefixes) assigned to this node in the tailnet (Go tailcfg.Node’s
Addresses []netip.Prefix).
A variable-length list, NOT a fixed (v4, v6) pair: a node on an IPv4-only tailnet
(e.g. an IPv6-off control plane / Headscale) is assigned only an IPv4 prefix, so this
has length 1. Modeling it as a 2-tuple broke deserialization against such control planes
(“invalid length 1, expected a tuple of size 2”). The domain Node picks the first IPv4
and (optionally) the first IPv6 prefix out of this list.
null tolerance is supplied by the struct-level #[serde_with::apply] block.
allowed_ips: Option<Vec<IpNet>>IP ranges to route to this node.
As of CapabilityVersion::V112, this may be null/undefined on the wire to indicate the
value is the same as Node::addresses. Once deserialized, it must always be populated,
even if those values are identical to Node::addresses.
endpoints: Vec<SocketAddr>IP addresses/ports that this node can be reached directly on.
Examples include public IP addresses/ports discovered via disco/STUN, or LAN-local IP addresses/ports.
legacy_derp_string: Option<RegionId>use Node::home_derp field instead
Deprecated. This node’s home DERP region ID, but shoved into an IP:port string for legacy
reasons. The IP address is always 127.3.3.40 (a loopback address (127) followed by the
number keys over the letters DERP on a QWERTY keyboard (3.3.40)). The “port number” is
the home DERP region ID.
The Node::home_derp field has replaced this since capability version 111, but old
servers might still send this field (see tailscale/tailscale#14636). Do not use this field
in code other than to upgrade/canonicalize the value to use Node::home_derp if a
"LegacyDERPString" field arrives on the wire.
home_derp: Option<RegionId>Unique ID of this node’s home DERP region.
May be zero if not yet known, but will ideally always be non-zero for normal connectivity; as DERP is used to discover direct connections, a home DERP region ID of zero prevents direct connection types from being discovered until its home DERP region ID is populated.
Preferred over the Node::legacy_derp_string field and supported by clients as of
CapabilityVersion 111.
host_info: HostInfo<'a>A summary of the host that a Tailscale node is running on. Includes information about the version of Tailscale running on the host, the operating system, running services, and various diagnostic/logging and configuration values.
Wire key Hostinfo — Go names the field Hostinfo (lowercase i, tailcfg.go:406), so serde
PascalCase (HostInfo) is wrong and a strict Go decoder drops it.
created: DateTime<Utc>The date/time this Tailscale node was created (added to the Tailnet for the first time).
cap: CapabilityVersionThe node’s CapabilityVersion; old servers may not send this value across the wire.
The list of ACL tags applied to this node. Tags take the form of tag:<value> where
<value> starts with a letter and only contains alphanumerics and dashes (-).
Some valid tag examples:
tag:prodtag:databasetag:lab-1
primary_routes: Vec<IpNet>The routes from Node::allowed_ips that this node is currently the primary subnet router
for, as determined by the control plane. It does not include the self address values from
Node::addresses that are in Node::allowed_ips.
last_seen: Option<DateTime<Utc>>When the node was last online. Only updated when Node::online is false. It is
None if the current node doesn’t have permission to know, or the node has never been
online.
online: Option<bool>Whether the node is currently connected to the control plane. A value of None means:
- The online status of the node is unknown
- The current node doesn’t have permission to know whether this node is online
- The node has never been online
Whether or not the Tailscale node is authorized to be part of the Tailnet.
capabilities: Vec<NodeCap<'a>>use Node::cap_map instead
Deprecated. Capabilities of this node.
They’re free-form strings, but should be in the form of URLs/URIs such as:
https://tailscale.com/cap/is-adminhttps://tailscale.com/cap/file-sharing
Replaced by the Node::cap_map field since capability version 89; use that field instead
(see tailscale/tailscale#11508).
cap_map: Map<'a>Map of capabilities to their optional argument/data values.
It is valid for a capability to not have any argument/data values. These type of
capabilities indicate that a node has a capability, but there is no additional data
associated with it. These were previously represented by the capabilities field,
but can now be represented by an entry in Node::cap_map with an empty value.
See NodeCap for more information on keys.
Metadata about nodes can be transmitted in 3 ways:
MapResponse::node::cap_mapdescribes attributes that affect behavior for this node, such as which features have been enabled through the admin panel and any associated configuration details.MapResponse::packet_filtersdescribes access (both IP- and application-based) that should be granted to peers.MapResponse::peers::cap_mapdescribes 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.
unsigned_peer_api_only: boolIndicates this node is not signed nor subject to Tailnet Key Authority (TKA) restrictions.
However, in exchange for that privilege, it does not get network access.It can only access
this node’s peerapi, which may not let it do anything. It is the Tailscale client’s job to
double-check the MapResponse::packet_filter field to
verify that its Node::allowed_ips will not be accepted by the packet filter.
data_plane_audit_log_id: &'a strThe per-node logtail ID used for data plane audit logging.
expired: boolWhether or not this node’s key has expired.
Control may send this; clients are only allowed to set this from false to true. On the
client, this is calculated client-side based on a timestamp sent from control to avoid
clock skew issues.
self_node_v4_masq_addr_for_this_peer: Option<IpAddr>The IPv4 address that this peer knows the current node as. It may be None if the peer
knows the current node by its native IPv4 address.
This field is only populated in MapResponse::peers, and will not be populated for the
current node. If set, it should be used to masquerade traffic originating from the current
node to this peer. The masquerade address is only relevant for this peer and not for other
peers. This only applies to traffic originating from the current node to the peer or any of
its subnets. Traffic originating from subnet routes will not be masqueraded (e.g. in case
of --snat-subnet-routes).
self_node_v6_masq_addr_for_this_peer: Option<IpAddr>The IPv6 address that this peer knows the current node as. It may be None if the peer
knows the current node by its native IPv6 address.
This field is only populated in MapResponse::peers, and will not be populated for the
current node. If set, it should be used to masquerade traffic originating from the current
node to this peer. The masquerade address is only relevant for this peer and not for other
peers. This only applies to traffic originating from the current node to the peer or any of
its subnets. Traffic originating from subnet routes will not be masqueraded (e.g. in case
of --snat-subnet-routes).
is_wireguard_only: boolIndicates that this is a non-Tailscale WireGuard peer.
WireGuard-only peers are not expected to speak Disco or DERP, and must have valid values in
Node::endpoints to be reachable.
is_jailed: boolIndicates that this node is jailed and should not be allowed initiate connections, but should be allowed to accept inbound connections.
exit_node_dns_resolvers: Vec<DnsResolver<'a>>The list of DNS servers that should be used when this node is WireGuard-only and being used as an exit node.