73 lines
2.1 KiB
Go
73 lines
2.1 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// Package proxymap contains a mapping table for ephemeral localhost ports used
|
|
// by tailscaled on behalf of remote Tailscale IPs for proxied connections.
|
|
package proxymap
|
|
|
|
import (
|
|
"net/netip"
|
|
"sync"
|
|
"time"
|
|
|
|
"tailscale.com/util/mak"
|
|
)
|
|
|
|
// Mapper tracks which localhost ip:ports correspond to which remote Tailscale
|
|
// IPs for connections proxied by tailscaled.
|
|
//
|
|
// This is then used (via the WhoIsIPPort method) by localhost applications to
|
|
// ask tailscaled (via the LocalAPI WhoIs method) the Tailscale identity that a
|
|
// given localhost:port corresponds to.
|
|
type Mapper struct {
|
|
mu sync.Mutex
|
|
m map[netip.AddrPort]netip.Addr
|
|
}
|
|
|
|
// RegisterIPPortIdentity registers a given node (identified by its
|
|
// Tailscale IP) as temporarily having the given IP:port for whois lookups.
|
|
// The IP:port is generally a localhost IP and an ephemeral port, used
|
|
// while proxying connections to localhost when tailscaled is running
|
|
// in netstack mode.
|
|
func (m *Mapper) RegisterIPPortIdentity(ipport netip.AddrPort, tsIP netip.Addr) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
mak.Set(&m.m, ipport, tsIP)
|
|
}
|
|
|
|
// UnregisterIPPortIdentity removes a temporary IP:port registration
|
|
// made previously by RegisterIPPortIdentity.
|
|
func (m *Mapper) UnregisterIPPortIdentity(ipport netip.AddrPort) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
delete(m.m, ipport)
|
|
}
|
|
|
|
var whoIsSleeps = [...]time.Duration{
|
|
0,
|
|
10 * time.Millisecond,
|
|
20 * time.Millisecond,
|
|
50 * time.Millisecond,
|
|
100 * time.Millisecond,
|
|
}
|
|
|
|
// WhoIsIPPort looks up an IP:port in the temporary registrations,
|
|
// and returns a matching Tailscale IP, if it exists.
|
|
func (m *Mapper) WhoIsIPPort(ipport netip.AddrPort) (tsIP netip.Addr, ok bool) {
|
|
// We currently have a registration race,
|
|
// https://github.com/tailscale/tailscale/issues/1616,
|
|
// so loop a few times for now waiting for the registration
|
|
// to appear.
|
|
// TODO(bradfitz,namansood): remove this once #1616 is fixed.
|
|
for _, d := range whoIsSleeps {
|
|
time.Sleep(d)
|
|
m.mu.Lock()
|
|
tsIP, ok = m.m[ipport]
|
|
m.mu.Unlock()
|
|
if ok {
|
|
return tsIP, true
|
|
}
|
|
}
|
|
return tsIP, false
|
|
}
|