The lazy init led to confusion and a belief that was something was
wrong. It's reasonable to expect the daemon to listen on the port at the
time it's configured.
Updates tailscale/corp#33094
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit also shuffles the hasPeerRelayServers atomic load
to happen sooner, reducing the cost for clients with no peer relay
servers.
Updates tailscale/corp#33099
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Switching to a Geneve-encapsulated (peer relay) path in
endpoint.handlePongConnLocked is expected around port rebinds, which end
up clearing endpoint.bestAddr.
Fixestailscale/corp#33036
Signed-off-by: Jordan Whited <jordan@tailscale.com>
endpointState is used for tracking UDP direct connection candidate
addresses. If it contains a DERP addr, then direct connection path
discovery will always send a wasteful disco ping over it. Additionally,
CLI "tailscale ping" via peer relay will race over DERP, leading to a
misleading result if pong arrives via DERP first.
Disco pongs arriving via DERP never influence path selection. Disco
ping/pong via DERP only serves "tailscale ping" reporting.
Updates #17121
Signed-off-by: Jordan Whited <jordan@tailscale.com>
To support integration testing of client features that rely on it, e.g.
peer relay.
Updates tailscale/corp#30903
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This increases throughput over long fat networks, and in the presence
of crypto/syscall-induced delay.
Updates tailscale/corp#31164
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This significantly improves throughput of a peer relay server on Linux.
Server.packetReadLoop no longer passes sockets down the stack. Instead,
packet handling methods return a netip.AddrPort and []byte, which
packetReadLoop gathers together for eventual batched writes on the
appropriate socket(s).
Updates tailscale/corp#31164
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Expected when Peer Relay'ing via self. These disco messages never get
sealed, and never leave the process.
Updates tailscale/corp#30527
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit also extends the updateRelayServersSet unit tests to cover
onNodeViewsUpdate.
Fixestailscale/corp#31080
Signed-off-by: Jordan Whited <jordan@tailscale.com>
One of these tests highlighted a Geneve encap bug, which is also fixed
in this commit.
looksLikeInitMsg was passed a packet post Geneve header stripping with
slice offsets that had not been updated to account for the stripping.
Updates tailscale/corp#30903
Signed-off-by: Jordan Whited <jordan@tailscale.com>
If a conn.Close call raced conn.ReadFromUDPAddrPort before it could
"register" itself as an active read, the conn.ReadFromUDPAddrPort would
never return.
This commit replaces all the activeRead and breakActiveReads machinery
with a channel. These constructs were only depended upon by
SetReadDeadline, and SetReadDeadline was unused.
Updates #16707
Signed-off-by: Jordan Whited <jordan@tailscale.com>
So that conn.PeerAwareEndpoint is always evaluated per-packet, rather
than at least once per packet batch.
Updates tailscale/corp#30042
Signed-off-by: Jordan Whited <jordan@tailscale.com>
A trusted peer relay path is always better than an untrusted direct or
peer relay path.
Updates tailscale/corp#30412
Signed-off-by: Jordan Whited <jordan@tailscale.com>
udpRelayEndpointReady used to write into the peerMap, which required
holding Conn.mu, but this changed in f9e7131.
Updates #cleanup
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Since a [*lazyEndpoint] makes wireguard-go responsible for peer ID, but
wireguard-go may not yet be configured for said peer, we need a JIT hook
around initiation message reception to call what is usually called from
an [*endpoint].
Updates tailscale/corp#30042
Signed-off-by: Jordan Whited <jordan@tailscale.com>
We can't relay a packet received over the IPv4 socket back out the same
socket if destined to an IPv6 address, and vice versa.
Updates tailscale/corp#30206
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Just make [relayManager] always handle it, there's no benefit to
checking bestAddr's.
Also, remove passing of disco.Pong to [relayManager] in
endpoint.handlePongConnLocked(), which is redundant with the callsite in
Conn.handleDiscoMessage(). Conn.handleDiscoMessage() already passes to
[relayManager] if the txID us not known to any [*endpoint].
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
A lazyEndpoint may end up on this TX codepath when wireguard-go is
deemed "under load" and ends up transmitting a cookie reply using the
received conn.Endpoint.
Updates tailscale/corp#20732
Updates tailscale/corp#30042
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Changes to our src/address family can trigger blackholes.
This commit also adds a missing set of trustBestAddrUntil when setting
a UDP relay path as bestAddr.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Otherwise we can end up mirroring packets to them forever. We may
eventually want to relax this to direct paths as well, but start with
UDP relay paths, which have a higher chance of becoming untrusted and
never working again, to be conservative.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This was previously hooked around direct UDP path discovery /
CallMeMaybe transmission, and related conditions. Now it is subject to
relay-specific considerations.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Relay handshakes may now occur multiple times over the lifetime of a
relay server endpoint. Handshake messages now include a handshake
generation, which is client specified, as a means to trigger safe
challenge reset server-side.
Relay servers continue to enforce challenge values as single use. They
will only send a given value once, in reply to the first arriving bind
message for a handshake generation.
VNI has been added to the handshake messages, and we expect the outer
Geneve header value to match the sealed value upon reception.
Remote peer disco pub key is now also included in handshake messages,
and it must match the receiver's expectation for the remote,
participating party.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Premature cancellation was preventing the work from ever being cleaned
up in runLoop().
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
If we acted as the allocator we are responsible for signaling it to the
remote peer in a CallMeMaybeVia message over DERP.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
udprelay.Server is lazily initialized when the first request is received
over peerAPI. These early requests have a high chance of failure until
the first address discovery cycle has completed.
Return an ErrServerNotReady error until the first address discovery
cycle has completed, and plumb retry handling for this error all the
way back to the client in relayManager.
relayManager can now retry after a few seconds instead of waiting for
the next path discovery cycle, which could take another minute or
longer.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This reverts commit 6a93b17c8c.
The reverted commit added more complexity than it was worth at the
current stage. Handling delta CapVer changes requires extensive changes
to relayManager datastructures in order to also support delta updates of
relay servers.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
The relay server now fetches IPs from local interfaces and external
perspective IP:port's via netcheck (STUN).
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This enables us to mark nodes as relay capable or not. We don't actually
do that yet, as we haven't established a relay CapVer.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
It might complete, interrupting it reduces the chances of establishing a
relay path.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This is simply for consistency with relayManagerInputEvent(), which
should be the sole launcher of runLoop().
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
relayManager can now hand endpoint a relay epAddr for it to consider
as bestAddr.
endpoint and Conn disco ping/pong handling are now VNI-aware.
Updates tailscale/corp#27502
Updates tailscale/corp#29422
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit adds a new type to magicsock, epAddr, which largely ends up
replacing netip.AddrPort in packet I/O paths throughout, enabling
Geneve encapsulation over UDP awareness.
The conn.ReceiveFunc for UDP has been revamped to fix and more clearly
distinguish the different classes of packets we expect to receive: naked
STUN binding messages, naked disco, naked WireGuard, Geneve-encapsulated
disco, and Geneve-encapsulated WireGuard.
Prior to this commit, STUN matching logic in the RX path could swallow
a naked WireGuard packet if the keypair index, which is randomly
generated, happened to overlap with a subset of the STUN magic cookie.
Updates tailscale/corp#27502
Updates tailscale/corp#29326
Signed-off-by: Jordan Whited <jordan@tailscale.com>
Our conn.Bind implementation is updated to make Send() offset-aware for
future VXLAN/Geneve encapsulation support.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
relayManager is responsible for disco ping/pong probing of relay
endpoints once a handshake is complete.
Future work will enable relayManager to set a relay endpoint as the best
UDP path on an endpoint if appropriate.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>
This type improves code clarity and reduces the chance of heap alloc as
we pass it as a non-pointer. VNI being a 3-byte value enables us to
track set vs unset via the reserved/unused byte.
Updates tailscale/corp#27502
Signed-off-by: Jordan Whited <jordan@tailscale.com>