mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-16 18:08:40 +00:00
wgengine, proxymap: split out port mapping from Engine to new type
(Continuing quest to remove rando stuff from the "Engine") Updates #cleanup Change-Id: I77f39902c2194410c10c054b545d70c9744250b0 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
db2f37d7c6
commit
3d37328af6
@ -289,6 +289,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/net/wsconn from tailscale.com/control/controlhttp+
|
||||
tailscale.com/paths from tailscale.com/ipn/ipnlocal+
|
||||
💣 tailscale.com/portlist from tailscale.com/ipn/ipnlocal
|
||||
tailscale.com/proxymap from tailscale.com/tsd+
|
||||
tailscale.com/safesocket from tailscale.com/client/tailscale+
|
||||
tailscale.com/smallzstd from tailscale.com/control/controlclient+
|
||||
LD 💣 tailscale.com/ssh/tailssh from tailscale.com/cmd/tailscaled
|
||||
|
@ -711,7 +711,14 @@ func runDebugServer(mux *http.ServeMux, addr string) {
|
||||
}
|
||||
|
||||
func newNetstack(logf logger.Logf, sys *tsd.System) (*netstack.Impl, error) {
|
||||
return netstack.Create(logf, sys.Tun.Get(), sys.Engine.Get(), sys.MagicSock.Get(), sys.Dialer.Get(), sys.DNSManager.Get())
|
||||
return netstack.Create(logf,
|
||||
sys.Tun.Get(),
|
||||
sys.Engine.Get(),
|
||||
sys.MagicSock.Get(),
|
||||
sys.Dialer.Get(),
|
||||
sys.DNSManager.Get(),
|
||||
sys.ProxyMapper(),
|
||||
)
|
||||
}
|
||||
|
||||
// mustStartProxyListeners creates listeners for local SOCKS and HTTP
|
||||
|
@ -109,7 +109,7 @@ func newIPN(jsConfig js.Value) map[string]any {
|
||||
}
|
||||
sys.Set(eng)
|
||||
|
||||
ns, err := netstack.Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get())
|
||||
ns, err := netstack.Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get(), sys.ProxyMapper())
|
||||
if err != nil {
|
||||
log.Fatalf("netstack.Create: %v", err)
|
||||
}
|
||||
|
@ -851,7 +851,7 @@ func (b *LocalBackend) WhoIs(ipp netip.AddrPort) (n tailcfg.NodeView, u tailcfg.
|
||||
if !ok {
|
||||
var ip netip.Addr
|
||||
if ipp.Port() != 0 {
|
||||
ip, ok = b.e.WhoIsIPPort(ipp)
|
||||
ip, ok = b.sys.ProxyMapper().WhoIsIPPort(ipp)
|
||||
}
|
||||
if !ok {
|
||||
return zero, u, false
|
||||
|
72
proxymap/proxymap.go
Normal file
72
proxymap/proxymap.go
Normal file
@ -0,0 +1,72 @@
|
||||
// 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
|
||||
}
|
10
tsd/tsd.go
10
tsd/tsd.go
@ -27,6 +27,7 @@ import (
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/net/tsdial"
|
||||
"tailscale.com/net/tstun"
|
||||
"tailscale.com/proxymap"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/wgengine"
|
||||
"tailscale.com/wgengine/magicsock"
|
||||
@ -45,7 +46,9 @@ type System struct {
|
||||
Tun SubSystem[*tstun.Wrapper]
|
||||
StateStore SubSystem[ipn.StateStore]
|
||||
Netstack SubSystem[NetstackImpl] // actually a *netstack.Impl
|
||||
controlKnobs controlknobs.Knobs
|
||||
|
||||
controlKnobs controlknobs.Knobs
|
||||
proxyMap proxymap.Mapper
|
||||
}
|
||||
|
||||
// NetstackImpl is the interface that *netstack.Impl implements.
|
||||
@ -103,6 +106,11 @@ func (s *System) ControlKnobs() *controlknobs.Knobs {
|
||||
return &s.controlKnobs
|
||||
}
|
||||
|
||||
// ProxyMapper returns the ephemeral ip:port mapper.
|
||||
func (s *System) ProxyMapper() *proxymap.Mapper {
|
||||
return &s.proxyMap
|
||||
}
|
||||
|
||||
// SubSystem represents some subsystem of the Tailscale node daemon.
|
||||
//
|
||||
// A subsystem can be set to a value, and then later retrieved. A subsystem
|
||||
|
@ -511,7 +511,7 @@ func (s *Server) start() (reterr error) {
|
||||
closePool.add(s.dialer)
|
||||
sys.Set(eng)
|
||||
|
||||
ns, err := netstack.Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), s.dialer, sys.DNSManager.Get())
|
||||
ns, err := netstack.Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), s.dialer, sys.DNSManager.Get(), sys.ProxyMapper())
|
||||
if err != nil {
|
||||
return fmt.Errorf("netstack.Create: %w", err)
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import (
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/net/tsdial"
|
||||
"tailscale.com/net/tstun"
|
||||
"tailscale.com/proxymap"
|
||||
"tailscale.com/syncs"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/ipproto"
|
||||
@ -121,6 +122,7 @@ type Impl struct {
|
||||
linkEP *channel.Endpoint
|
||||
tundev *tstun.Wrapper
|
||||
e wgengine.Engine
|
||||
pm *proxymap.Mapper
|
||||
mc *magicsock.Conn
|
||||
logf logger.Logf
|
||||
dialer *tsdial.Dialer
|
||||
@ -154,7 +156,7 @@ const nicID = 1
|
||||
const maxUDPPacketSize = 1500
|
||||
|
||||
// Create creates and populates a new Impl.
|
||||
func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magicsock.Conn, dialer *tsdial.Dialer, dns *dns.Manager) (*Impl, error) {
|
||||
func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magicsock.Conn, dialer *tsdial.Dialer, dns *dns.Manager, pm *proxymap.Mapper) (*Impl, error) {
|
||||
if mc == nil {
|
||||
return nil, errors.New("nil magicsock.Conn")
|
||||
}
|
||||
@ -167,6 +169,9 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi
|
||||
if e == nil {
|
||||
return nil, errors.New("nil Engine")
|
||||
}
|
||||
if pm == nil {
|
||||
return nil, errors.New("nil proxymap.Mapper")
|
||||
}
|
||||
if dialer == nil {
|
||||
return nil, errors.New("nil Dialer")
|
||||
}
|
||||
@ -209,6 +214,7 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi
|
||||
linkEP: linkEP,
|
||||
tundev: tundev,
|
||||
e: e,
|
||||
pm: pm,
|
||||
mc: mc,
|
||||
dialer: dialer,
|
||||
connsOpenBySubnetIP: make(map[netip.Addr]int),
|
||||
@ -984,8 +990,8 @@ func (ns *Impl) forwardTCP(getClient func(...tcpip.SettableSocketOption) *gonet.
|
||||
|
||||
backendLocalAddr := server.LocalAddr().(*net.TCPAddr)
|
||||
backendLocalIPPort := netaddr.Unmap(backendLocalAddr.AddrPort())
|
||||
ns.e.RegisterIPPortIdentity(backendLocalIPPort, clientRemoteIP)
|
||||
defer ns.e.UnregisterIPPortIdentity(backendLocalIPPort)
|
||||
ns.pm.RegisterIPPortIdentity(backendLocalIPPort, clientRemoteIP)
|
||||
defer ns.pm.UnregisterIPPortIdentity(backendLocalIPPort)
|
||||
connClosed := make(chan error, 2)
|
||||
go func() {
|
||||
_, err := io.Copy(server, client)
|
||||
@ -1135,7 +1141,7 @@ func (ns *Impl) forwardUDP(client *gonet.UDPConn, clientAddr, dstAddr netip.Addr
|
||||
ns.logf("could not get backend local IP:port from %v:%v", backendLocalAddr.IP, backendLocalAddr.Port)
|
||||
}
|
||||
if isLocal {
|
||||
ns.e.RegisterIPPortIdentity(backendLocalIPPort, dstAddr.Addr())
|
||||
ns.pm.RegisterIPPortIdentity(backendLocalIPPort, dstAddr.Addr())
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
@ -1151,7 +1157,7 @@ func (ns *Impl) forwardUDP(client *gonet.UDPConn, clientAddr, dstAddr netip.Addr
|
||||
}
|
||||
timer := time.AfterFunc(idleTimeout, func() {
|
||||
if isLocal {
|
||||
ns.e.UnregisterIPPortIdentity(backendLocalIPPort)
|
||||
ns.pm.UnregisterIPPortIdentity(backendLocalIPPort)
|
||||
}
|
||||
ns.logf("netstack: UDP session between %s and %s timed out", backendListenAddr, backendRemoteAddr)
|
||||
cancel()
|
||||
|
@ -53,7 +53,7 @@ func TestInjectInboundLeak(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ns, err := Create(logf, tunWrap, eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get())
|
||||
ns, err := Create(logf, tunWrap, eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get(), sys.ProxyMapper())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -102,7 +102,7 @@ func makeNetstack(t *testing.T, config func(*Impl)) *Impl {
|
||||
t.Cleanup(func() { eng.Close() })
|
||||
sys.Set(eng)
|
||||
|
||||
ns, err := Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get())
|
||||
ns, err := Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get(), sys.ProxyMapper())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -133,7 +133,6 @@ type userspaceEngine struct {
|
||||
peerSequence []key.NodePublic
|
||||
endpoints []tailcfg.Endpoint
|
||||
pendOpen map[flowtrack.Tuple]*pendingOpenFlow // see pendopen.go
|
||||
tsIPByIPPort map[netip.AddrPort]netip.Addr // allows registration of IP:ports as belonging to a certain Tailscale IP for whois lookups
|
||||
|
||||
// pongCallback is the map of response handlers waiting for disco or TSMP
|
||||
// pong callbacks. The map key is a random slice of bytes.
|
||||
@ -1341,50 +1340,6 @@ func (e *userspaceEngine) setICMPEchoResponseCallback(idSeq uint32, cb func()) {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *userspaceEngine) RegisterIPPortIdentity(ipport netip.AddrPort, tsIP netip.Addr) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
if e.tsIPByIPPort == nil {
|
||||
e.tsIPByIPPort = make(map[netip.AddrPort]netip.Addr)
|
||||
}
|
||||
e.tsIPByIPPort[ipport] = tsIP
|
||||
}
|
||||
|
||||
func (e *userspaceEngine) UnregisterIPPortIdentity(ipport netip.AddrPort) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
if e.tsIPByIPPort == nil {
|
||||
return
|
||||
}
|
||||
delete(e.tsIPByIPPort, ipport)
|
||||
}
|
||||
|
||||
var whoIsSleeps = [...]time.Duration{
|
||||
0,
|
||||
10 * time.Millisecond,
|
||||
20 * time.Millisecond,
|
||||
50 * time.Millisecond,
|
||||
100 * time.Millisecond,
|
||||
}
|
||||
|
||||
func (e *userspaceEngine) 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)
|
||||
e.mu.Lock()
|
||||
tsIP, ok = e.tsIPByIPPort[ipport]
|
||||
e.mu.Unlock()
|
||||
if ok {
|
||||
return tsIP, true
|
||||
}
|
||||
}
|
||||
return tsIP, false
|
||||
}
|
||||
|
||||
// PeerForIP returns the Node in the wireguard config
|
||||
// that's responsible for handling the given IP address.
|
||||
//
|
||||
|
@ -142,16 +142,6 @@ func (e *watchdogEngine) SetNetworkMap(nm *netmap.NetworkMap) {
|
||||
func (e *watchdogEngine) Ping(ip netip.Addr, pingType tailcfg.PingType, size int, cb func(*ipnstate.PingResult)) {
|
||||
e.watchdog("Ping", func() { e.wrap.Ping(ip, pingType, size, cb) })
|
||||
}
|
||||
func (e *watchdogEngine) RegisterIPPortIdentity(ipp netip.AddrPort, tsIP netip.Addr) {
|
||||
e.watchdog("RegisterIPPortIdentity", func() { e.wrap.RegisterIPPortIdentity(ipp, tsIP) })
|
||||
}
|
||||
func (e *watchdogEngine) UnregisterIPPortIdentity(ipp netip.AddrPort) {
|
||||
e.watchdog("UnregisterIPPortIdentity", func() { e.wrap.UnregisterIPPortIdentity(ipp) })
|
||||
}
|
||||
func (e *watchdogEngine) WhoIsIPPort(ipp netip.AddrPort) (tsIP netip.Addr, ok bool) {
|
||||
e.watchdog("UnregisterIPPortIdentity", func() { tsIP, ok = e.wrap.WhoIsIPPort(ipp) })
|
||||
return tsIP, ok
|
||||
}
|
||||
func (e *watchdogEngine) Close() {
|
||||
e.watchdog("Close", e.wrap.Close)
|
||||
}
|
||||
|
@ -111,21 +111,6 @@ type Engine interface {
|
||||
// If size is zero too small, it is ignored. See tailscale.PingOpts for details.
|
||||
Ping(ip netip.Addr, pingType tailcfg.PingType, size int, cb func(*ipnstate.PingResult))
|
||||
|
||||
// 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.
|
||||
RegisterIPPortIdentity(netip.AddrPort, netip.Addr)
|
||||
|
||||
// UnregisterIPPortIdentity removes a temporary IP:port registration
|
||||
// made previously by RegisterIPPortIdentity.
|
||||
UnregisterIPPortIdentity(netip.AddrPort)
|
||||
|
||||
// WhoIsIPPort looks up an IP:port in the temporary registrations,
|
||||
// and returns a matching Tailscale IP, if it exists.
|
||||
WhoIsIPPort(netip.AddrPort) (netip.Addr, bool)
|
||||
|
||||
// InstallCaptureHook registers a function to be called to capture
|
||||
// packets traversing the data path. The hook can be uninstalled by
|
||||
// calling this function with a nil value.
|
||||
|
Loading…
x
Reference in New Issue
Block a user