|
@@ -6,9 +6,13 @@
|
|
|
package proxymap
|
|
package proxymap
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
|
+ "fmt"
|
|
|
"net/netip"
|
|
"net/netip"
|
|
|
|
|
+ "strings"
|
|
|
"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
|
|
@@ -24,7 +28,26 @@ type Mapper struct {
|
|
|
// keyed first by the protocol ("tcp" or "udp"), then by the IP:port.
|
|
// keyed first by the protocol ("tcp" or "udp"), then by the IP:port.
|
|
|
//
|
|
//
|
|
|
// +checklocks:mu
|
|
// +checklocks:mu
|
|
|
- m map[string]map[netip.AddrPort]netip.Addr
|
|
|
|
|
|
|
+ m map[mappingKey]netip.Addr
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// String returns a human-readable representation of the current mappings.
|
|
|
|
|
+func (m *Mapper) String() string {
|
|
|
|
|
+ m.mu.Lock()
|
|
|
|
|
+ defer m.mu.Unlock()
|
|
|
|
|
+ if len(m.m) == 0 {
|
|
|
|
|
+ return "no mappings"
|
|
|
|
|
+ }
|
|
|
|
|
+ var sb strings.Builder
|
|
|
|
|
+ for k, v := range m.m {
|
|
|
|
|
+ fmt.Fprintf(&sb, "%v/%v=>%v\n", k.proto, k.ap, v)
|
|
|
|
|
+ }
|
|
|
|
|
+ return sb.String()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type mappingKey struct {
|
|
|
|
|
+ proto string
|
|
|
|
|
+ ap netip.AddrPort
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// RegisterIPPortIdentity registers a given node (identified by its
|
|
// RegisterIPPortIdentity registers a given node (identified by its
|
|
@@ -36,18 +59,15 @@ type Mapper struct {
|
|
|
//
|
|
//
|
|
|
// The proto is the network protocol that is being proxied; it must be "tcp" or
|
|
// The proto is the network protocol that is being proxied; it must be "tcp" or
|
|
|
// "udp" (not e.g. "tcp4", "udp6", etc.)
|
|
// "udp" (not e.g. "tcp4", "udp6", etc.)
|
|
|
-func (m *Mapper) RegisterIPPortIdentity(proto string, ipport netip.AddrPort, tsIP netip.Addr) {
|
|
|
|
|
|
|
+func (m *Mapper) RegisterIPPortIdentity(proto string, ipport netip.AddrPort, tsIP netip.Addr) error {
|
|
|
m.mu.Lock()
|
|
m.mu.Lock()
|
|
|
defer m.mu.Unlock()
|
|
defer m.mu.Unlock()
|
|
|
- if m.m == nil {
|
|
|
|
|
- m.m = make(map[string]map[netip.AddrPort]netip.Addr)
|
|
|
|
|
|
|
+ k := mappingKey{proto, ipport}
|
|
|
|
|
+ if v, ok := m.m[k]; ok {
|
|
|
|
|
+ return fmt.Errorf("proxymap: RegisterIPPortIdentity: already registered: %v/%v=>%v", k.proto, k.ap, v)
|
|
|
}
|
|
}
|
|
|
- p, ok := m.m[proto]
|
|
|
|
|
- if !ok {
|
|
|
|
|
- p = make(map[netip.AddrPort]netip.Addr)
|
|
|
|
|
- m.m[proto] = p
|
|
|
|
|
- }
|
|
|
|
|
- p[ipport] = tsIP
|
|
|
|
|
|
|
+ mak.Set(&m.m, k, tsIP)
|
|
|
|
|
+ return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// UnregisterIPPortIdentity removes a temporary IP:port registration
|
|
// UnregisterIPPortIdentity removes a temporary IP:port registration
|
|
@@ -55,8 +75,8 @@ func (m *Mapper) RegisterIPPortIdentity(proto string, ipport netip.AddrPort, tsI
|
|
|
func (m *Mapper) UnregisterIPPortIdentity(proto string, 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()
|
|
|
- p := m.m[proto]
|
|
|
|
|
- delete(p, ipport) // safe to delete from a nil map
|
|
|
|
|
|
|
+ k := mappingKey{proto, ipport}
|
|
|
|
|
+ delete(m.m, k) // safe to delete from a nil map
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var whoIsSleeps = [...]time.Duration{
|
|
var whoIsSleeps = [...]time.Duration{
|
|
@@ -75,13 +95,11 @@ func (m *Mapper) WhoIsIPPort(proto string, ipport netip.AddrPort) (tsIP netip.Ad
|
|
|
// so loop a few times for now waiting for the registration
|
|
// so loop a few times for now waiting for the registration
|
|
|
// to appear.
|
|
// to appear.
|
|
|
// TODO(bradfitz,namansood): remove this once #1616 is fixed.
|
|
// TODO(bradfitz,namansood): remove this once #1616 is fixed.
|
|
|
|
|
+ k := mappingKey{proto, ipport}
|
|
|
for _, d := range whoIsSleeps {
|
|
for _, d := range whoIsSleeps {
|
|
|
time.Sleep(d)
|
|
time.Sleep(d)
|
|
|
m.mu.Lock()
|
|
m.mu.Lock()
|
|
|
- p, ok := m.m[proto]
|
|
|
|
|
- if ok {
|
|
|
|
|
- tsIP, ok = p[ipport]
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ tsIP, ok := m.m[k]
|
|
|
m.mu.Unlock()
|
|
m.mu.Unlock()
|
|
|
if ok {
|
|
if ok {
|
|
|
return tsIP, true
|
|
return tsIP, true
|