mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-20 11:58:39 +00:00
wgengine/magicsock: use learned DERP route as send path of last resort
If we get a packet in over some DERP and don't otherwise know how to reply (no known DERP home or UDP endpoint), this makes us use the DERP connection on which we received the packet to reply. This will almost always be our own home DERP region. This is particularly useful for large one-way nodes (such as hello.ts.net) that don't actively reach out to other nodes, so don't need to be told the DERP home of peers. They can instead learn the DERP home upon getting the first connection. This can also help nodes from a slow or misbehaving control plane. Updates tailscale/corp#26438 Change-Id: I6241ec92828bf45982e0eb83ad5c7404df5968bc Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
7b3e5b5df3
commit
cd76392f0c
@ -64,10 +64,30 @@ func (c *Conn) removeDerpPeerRoute(peer key.NodePublic, regionID int, dc *derpht
|
||||
// addDerpPeerRoute adds a DERP route entry, noting that peer was seen
|
||||
// on DERP node derpID, at least on the connection identified by dc.
|
||||
// See issue 150 for details.
|
||||
func (c *Conn) addDerpPeerRoute(peer key.NodePublic, derpID int, dc *derphttp.Client) {
|
||||
func (c *Conn) addDerpPeerRoute(peer key.NodePublic, regionID int, dc *derphttp.Client) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
mak.Set(&c.derpRoute, peer, derpRoute{derpID, dc})
|
||||
mak.Set(&c.derpRoute, peer, derpRoute{regionID, dc})
|
||||
}
|
||||
|
||||
// fallbackDERPRegionForPeer returns the DERP region ID we might be able to use
|
||||
// to contact peer, learned from observing recent DERP traffic from them.
|
||||
//
|
||||
// This is used as a fallback when a peer receives a packet from a peer
|
||||
// peer over DERP but doesn't known that peer's home DERP or any UDP endpoints.
|
||||
// This is particularly useful for large one-way nodes (such as hello.ts.net)
|
||||
// that don't actively reach out to other nodes, so don't need to be told
|
||||
// the DERP home of peers. They can instead learn the DERP home upon getting the
|
||||
// first connection.
|
||||
//
|
||||
// This can also help nodes from a slow or misbehaving control plane.
|
||||
func (c *Conn) fallbackDERPRegionForPeer(peer key.NodePublic) (regionID int) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if dr, ok := c.derpRoute[peer]; ok {
|
||||
return dr.regionID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// activeDerp contains fields for an active DERP connection.
|
||||
|
@ -948,7 +948,15 @@ func (de *endpoint) send(buffs [][]byte) error {
|
||||
de.mu.Unlock()
|
||||
|
||||
if !udpAddr.IsValid() && !derpAddr.IsValid() {
|
||||
return errNoUDPOrDERP
|
||||
// Make a last ditch effort to see if we have a DERP route for them. If
|
||||
// they contacted us over DERP and we don't know their UDP endpoints or
|
||||
// their DERP home, we can at least assume they're reachable over the
|
||||
// DERP they used to contact us.
|
||||
if rid := de.c.fallbackDERPRegionForPeer(de.publicKey); rid != 0 {
|
||||
derpAddr = netip.AddrPortFrom(tailcfg.DerpMagicIPAddr, uint16(rid))
|
||||
} else {
|
||||
return errNoUDPOrDERP
|
||||
}
|
||||
}
|
||||
var err error
|
||||
if udpAddr.IsValid() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user