@ -9,8 +9,6 @@ import (
"net/netip"
"net/netip"
"sync"
"sync"
"time"
"time"
"tailscale.com/util/mak"
)
)
// Mapper tracks which localhost ip:ports correspond to which remote Tailscale
// Mapper tracks which localhost ip:ports correspond to which remote Tailscale
@ -21,26 +19,39 @@ import (
// given localhost:port corresponds to.
// given localhost:port corresponds to.
type Mapper struct {
type Mapper struct {
mu sync . Mutex
mu sync . Mutex
m map [ netip . AddrPort ] netip . Addr
m map [ string ] map [ netip . AddrPort ] netip . Addr // proto ("tcp", "udp") => ephemeral => tailscale IP
}
}
// RegisterIPPortIdentity registers a given node (identified by its
// RegisterIPPortIdentity registers a given node (identified by its
// Tailscale IP) as temporarily having the given IP:port for whois lookups.
// 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
// The IP:port is generally a localhost IP and an ephemeral port, used
// while proxying connections to localhost when tailscaled is running
// while proxying connections to localhost when tailscaled is running
// in netstack mode.
// in netstack mode.
func ( m * Mapper ) RegisterIPPortIdentity ( ipport netip . AddrPort , tsIP netip . Addr ) {
//
// The proto is the network protocol that is being proxied; it must be "tcp" or
// "udp" (not e.g. "tcp4", "udp6", etc.)
func ( m * Mapper ) RegisterIPPortIdentity ( proto string , ipport netip . AddrPort , tsIP netip . Addr ) {
m . mu . Lock ( )
m . mu . Lock ( )
defer m . mu . Unlock ( )
defer m . mu . Unlock ( )
mak . Set ( & m . m , ipport , tsIP )
if m . m == nil {
m . m = make ( map [ string ] map [ netip . AddrPort ] netip . Addr )
}
p , ok := m . m [ proto ]
if ! ok {
p = make ( map [ netip . AddrPort ] netip . Addr )
m . m [ proto ] = p
}
p [ ipport ] = tsIP
}
}
// UnregisterIPPortIdentity removes a temporary IP:port registration
// UnregisterIPPortIdentity removes a temporary IP:port registration
// made previously by RegisterIPPortIdentity.
// made previously by RegisterIPPortIdentity.
func ( m * Mapper ) UnregisterIPPortIdentity ( ipport netip . AddrPort ) {
func ( m * Mapper ) UnregisterIPPortIdentity ( proto string , ipport netip . AddrPort ) {
m . mu . Lock ( )
m . mu . Lock ( )
defer m . mu . Unlock ( )
defer m . mu . Unlock ( )
delete ( m . m , ipport )
p := m . m [ proto ]
delete ( p , ipport ) // safe to delete from a nil map
}
}
var whoIsSleeps = [ ... ] time . Duration {
var whoIsSleeps = [ ... ] time . Duration {
@ -53,7 +64,7 @@ var whoIsSleeps = [...]time.Duration{
// WhoIsIPPort looks up an IP:port in the temporary registrations,
// WhoIsIPPort looks up an IP:port in the temporary registrations,
// and returns a matching Tailscale IP, if it exists.
// and returns a matching Tailscale IP, if it exists.
func ( m * Mapper ) WhoIsIPPort ( ipport netip . AddrPort ) ( tsIP netip . Addr , ok bool ) {
func ( m * Mapper ) WhoIsIPPort ( proto string , ipport netip . AddrPort ) ( tsIP netip . Addr , ok bool ) {
// We currently have a registration race,
// We currently have a registration race,
// https://github.com/tailscale/tailscale/issues/1616,
// https://github.com/tailscale/tailscale/issues/1616,
// so loop a few times for now waiting for the registration
// so loop a few times for now waiting for the registration
@ -62,7 +73,10 @@ func (m *Mapper) WhoIsIPPort(ipport netip.AddrPort) (tsIP netip.Addr, ok bool) {
for _ , d := range whoIsSleeps {
for _ , d := range whoIsSleeps {
time . Sleep ( d )
time . Sleep ( d )
m . mu . Lock ( )
m . mu . Lock ( )
tsIP , ok = m . m [ ipport ]
p , ok := m . m [ proto ]
if ok {
tsIP , ok = p [ ipport ]
}
m . mu . Unlock ( )
m . mu . Unlock ( )
if ok {
if ok {
return tsIP , true
return tsIP , true