Compare commits
1 Commits
Xe/do-wind
...
bradfitz/a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b2b679ba3 |
@@ -120,11 +120,6 @@ func checkIPForwarding() {
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
ipv4default = netaddr.MustParseIPPrefix("0.0.0.0/0")
|
||||
ipv6default = netaddr.MustParseIPPrefix("::/0")
|
||||
)
|
||||
|
||||
func runUp(ctx context.Context, args []string) error {
|
||||
if len(args) > 0 {
|
||||
log.Fatalf("too many non-flag arguments: %q", args)
|
||||
@@ -144,7 +139,6 @@ func runUp(ctx context.Context, args []string) error {
|
||||
}
|
||||
|
||||
var routes []netaddr.IPPrefix
|
||||
var default4, default6 bool
|
||||
if upArgs.advertiseRoutes != "" {
|
||||
advroutes := strings.Split(upArgs.advertiseRoutes, ",")
|
||||
for _, s := range advroutes {
|
||||
@@ -155,18 +149,8 @@ func runUp(ctx context.Context, args []string) error {
|
||||
if ipp != ipp.Masked() {
|
||||
fatalf("%s has non-address bits set; expected %s", ipp, ipp.Masked())
|
||||
}
|
||||
if ipp == ipv4default {
|
||||
default4 = true
|
||||
} else if ipp == ipv6default {
|
||||
default6 = true
|
||||
}
|
||||
routes = append(routes, ipp)
|
||||
}
|
||||
if default4 && !default6 {
|
||||
fatalf("%s advertised without its IPv6 counterpart, please also advertise %s", ipv4default, ipv6default)
|
||||
} else if default6 && !default4 {
|
||||
fatalf("%s advertised without its IPv6 counterpart, please also advertise %s", ipv6default, ipv4default)
|
||||
}
|
||||
checkIPForwarding()
|
||||
}
|
||||
|
||||
|
||||
@@ -744,14 +744,6 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*Netw
|
||||
}
|
||||
resp.Peers = filtered
|
||||
}
|
||||
if Debug.StripEndpoints {
|
||||
for _, p := range resp.Peers {
|
||||
// We need at least one endpoint here for now else
|
||||
// other code doesn't even create the discoEndpoint.
|
||||
// TODO(bradfitz): fix that and then just nil this out.
|
||||
p.Endpoints = []string{"127.9.9.9:456"}
|
||||
}
|
||||
}
|
||||
|
||||
if pf := resp.PacketFilter; pf != nil {
|
||||
lastParsedPacketFilter = c.parsePacketFilter(pf)
|
||||
@@ -980,21 +972,19 @@ func loadServerKey(ctx context.Context, httpc *http.Client, serverURL string) (w
|
||||
var Debug = initDebug()
|
||||
|
||||
type debug struct {
|
||||
NetMap bool
|
||||
ProxyDNS bool
|
||||
OnlyDisco bool
|
||||
Disco bool
|
||||
StripEndpoints bool // strip endpoints from control (only use disco messages)
|
||||
NetMap bool
|
||||
ProxyDNS bool
|
||||
OnlyDisco bool
|
||||
Disco bool
|
||||
}
|
||||
|
||||
func initDebug() debug {
|
||||
use := os.Getenv("TS_DEBUG_USE_DISCO")
|
||||
return debug{
|
||||
NetMap: envBool("TS_DEBUG_NETMAP"),
|
||||
ProxyDNS: envBool("TS_DEBUG_PROXY_DNS"),
|
||||
StripEndpoints: envBool("TS_DEBUG_STRIP_ENDPOINTS"),
|
||||
OnlyDisco: use == "only",
|
||||
Disco: use == "only" || use == "" || envBool("TS_DEBUG_USE_DISCO"),
|
||||
NetMap: envBool("TS_DEBUG_NETMAP"),
|
||||
ProxyDNS: envBool("TS_DEBUG_PROXY_DNS"),
|
||||
OnlyDisco: use == "only",
|
||||
Disco: use == "only" || use == "" || envBool("TS_DEBUG_USE_DISCO"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,24 +1065,6 @@ func undeltaPeers(mapRes *tailcfg.MapResponse, prev []*tailcfg.Node) {
|
||||
}
|
||||
}
|
||||
sortNodes(newFull)
|
||||
|
||||
if mapRes.PeerSeenChange != nil {
|
||||
peerByID := make(map[tailcfg.NodeID]*tailcfg.Node, len(newFull))
|
||||
for _, n := range newFull {
|
||||
peerByID[n.ID] = n
|
||||
}
|
||||
now := time.Now()
|
||||
for nodeID, seen := range mapRes.PeerSeenChange {
|
||||
if n, ok := peerByID[nodeID]; ok {
|
||||
if seen {
|
||||
n.LastSeen = &now
|
||||
} else {
|
||||
n.LastSeen = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapRes.Peers = newFull
|
||||
mapRes.PeersChanged = nil
|
||||
mapRes.PeersRemoved = nil
|
||||
|
||||
@@ -312,14 +312,12 @@ func (nm *NetworkMap) WGCfg(logf logger.Logf, flags WGConfigFlags) (*wgcfg.Confi
|
||||
for _, allowedIP := range peer.AllowedIPs {
|
||||
if allowedIP.Bits == 0 {
|
||||
if (flags & AllowDefaultRoute) == 0 {
|
||||
logf("[v1] wgcfg: not accepting default route from %q (%v)",
|
||||
nodeDebugName(peer), peer.Key.ShortString())
|
||||
logf("[v1] wgcfg: %v skipping default route", peer.Key.ShortString())
|
||||
continue
|
||||
}
|
||||
} else if cidrIsSubnet(peer, allowedIP) {
|
||||
if (flags & AllowSubnetRoutes) == 0 {
|
||||
logf("[v1] wgcfg: not accepting subnet route %v from %q (%v)",
|
||||
allowedIP, nodeDebugName(peer), peer.Key.ShortString())
|
||||
logf("[v1] wgcfg: %v skipping subnet route", peer.Key.ShortString())
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -330,20 +328,6 @@ func (nm *NetworkMap) WGCfg(logf logger.Logf, flags WGConfigFlags) (*wgcfg.Confi
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func nodeDebugName(n *tailcfg.Node) string {
|
||||
name := n.Name
|
||||
if name == "" {
|
||||
name = n.Hostinfo.Hostname
|
||||
}
|
||||
if i := strings.Index(name, "."); i != -1 {
|
||||
name = name[:i]
|
||||
}
|
||||
if name == "" && len(n.Addresses) != 0 {
|
||||
return n.Addresses[0].String()
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// cidrIsSubnet reports whether cidr is a non-default-route subnet
|
||||
// exported by node that is not one of its own self addresses.
|
||||
func cidrIsSubnet(node *tailcfg.Node, cidr netaddr.IPPrefix) bool {
|
||||
|
||||
@@ -70,7 +70,7 @@ func Parse(p []byte) (Message, error) {
|
||||
case TypePong:
|
||||
return parsePong(ver, p)
|
||||
case TypeCallMeMaybe:
|
||||
return parseCallMeMaybe(ver, p)
|
||||
return CallMeMaybe{}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown message type 0x%02x", byte(t))
|
||||
}
|
||||
@@ -122,57 +122,13 @@ func parsePing(ver uint8, p []byte) (m *Ping, err error) {
|
||||
//
|
||||
// The recipient may choose to not open a path back, if it's already
|
||||
// happy with its path. But usually it will.
|
||||
type CallMeMaybe struct {
|
||||
// MyNumber is what the peer believes its endpoints are.
|
||||
//
|
||||
// Prior to Tailscale 1.4, the endpoints were exchanged purely
|
||||
// between nodes and the control server.
|
||||
//
|
||||
// Starting with Tailscale 1.4, clients advertise their endpoints.
|
||||
// Older clients won't use this, but newer clients should
|
||||
// use any endpoints in here that aren't included from control.
|
||||
//
|
||||
// Control might have sent stale endpoints if the client was idle
|
||||
// before contacting us. In that case, the client likely did a STUN
|
||||
// request immediately before sending the CallMeMaybe to recreate
|
||||
// their NAT port mapping, and that new good endpoint is included
|
||||
// in this field, but might not yet be in control's endpoints.
|
||||
// (And in the future, control will stop distributing endpoints
|
||||
// when clients are suitably new.)
|
||||
MyNumber []netaddr.IPPort
|
||||
}
|
||||
type CallMeMaybe struct{}
|
||||
|
||||
const epLength = 16 + 2 // 16 byte IP address + 2 byte port
|
||||
|
||||
func (m *CallMeMaybe) AppendMarshal(b []byte) []byte {
|
||||
ret, p := appendMsgHeader(b, TypeCallMeMaybe, v0, epLength*len(m.MyNumber))
|
||||
for _, ipp := range m.MyNumber {
|
||||
a := ipp.IP.As16()
|
||||
copy(p[:], a[:])
|
||||
binary.BigEndian.PutUint16(p[16:], ipp.Port)
|
||||
p = p[epLength:]
|
||||
}
|
||||
func (CallMeMaybe) AppendMarshal(b []byte) []byte {
|
||||
ret, _ := appendMsgHeader(b, TypeCallMeMaybe, v0, 0)
|
||||
return ret
|
||||
}
|
||||
|
||||
func parseCallMeMaybe(ver uint8, p []byte) (m *CallMeMaybe, err error) {
|
||||
m = new(CallMeMaybe)
|
||||
if len(p)%epLength != 0 || ver != 0 || len(p) == 0 {
|
||||
return m, nil
|
||||
}
|
||||
m.MyNumber = make([]netaddr.IPPort, 0, len(p)/epLength)
|
||||
for len(p) > 0 {
|
||||
var a [16]byte
|
||||
copy(a[:], p)
|
||||
m.MyNumber = append(m.MyNumber, netaddr.IPPort{
|
||||
IP: netaddr.IPFrom16(a),
|
||||
Port: binary.BigEndian.Uint16(p[16:18]),
|
||||
})
|
||||
p = p[epLength:]
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Pong is a response a Ping.
|
||||
//
|
||||
// It includes the sender's source IP + port, so it's effectively a
|
||||
@@ -215,7 +171,7 @@ func MessageSummary(m Message) string {
|
||||
return fmt.Sprintf("ping tx=%x", m.TxID[:6])
|
||||
case *Pong:
|
||||
return fmt.Sprintf("pong tx=%x", m.TxID[:6])
|
||||
case *CallMeMaybe:
|
||||
case CallMeMaybe:
|
||||
return "call-me-maybe"
|
||||
default:
|
||||
return fmt.Sprintf("%#v", m)
|
||||
|
||||
@@ -44,19 +44,9 @@ func TestMarshalAndParse(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "call_me_maybe",
|
||||
m: &CallMeMaybe{},
|
||||
m: CallMeMaybe{},
|
||||
want: "03 00",
|
||||
},
|
||||
{
|
||||
name: "call_me_maybe_endpoints",
|
||||
m: &CallMeMaybe{
|
||||
MyNumber: []netaddr.IPPort{
|
||||
netaddr.MustParseIPPort("1.2.3.4:567"),
|
||||
netaddr.MustParseIPPort("[2001::3456]:789"),
|
||||
},
|
||||
},
|
||||
want: "03 00 00 00 00 00 00 00 00 00 00 00 ff ff 01 02 03 04 02 37 20 01 00 00 00 00 00 00 00 00 00 00 00 00 34 56 03 15",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -429,10 +429,6 @@ func (b *LocalBackend) Start(opts Options) error {
|
||||
return fmt.Errorf("loading requested state: %v", err)
|
||||
}
|
||||
|
||||
if b.prefs.LogServer == "" {
|
||||
b.prefs.LogServer = "https://log.tailscale.io"
|
||||
}
|
||||
os.Setenv("TAILSCALE_LOG_TARGET", b.prefs.LogServer)
|
||||
b.inServerMode = b.prefs.ForceDaemon
|
||||
b.serverURL = b.prefs.ControlURL
|
||||
hostinfo.RoutableIPs = append(hostinfo.RoutableIPs, b.prefs.AdvertiseRoutes...)
|
||||
|
||||
@@ -124,10 +124,6 @@ type Prefs struct {
|
||||
// We can maybe do that once we're sure which module should persist
|
||||
// it (backend or frontend?)
|
||||
Persist *controlclient.Persist `json:"Config"`
|
||||
|
||||
// The target server where logs should be sent. If not set this will
|
||||
// default to https://log.tailscale.io.
|
||||
LogServer string
|
||||
}
|
||||
|
||||
// IsEmpty reports whether p is nil or pointing to a Prefs zero value.
|
||||
|
||||
@@ -48,5 +48,4 @@ var _PrefsNeedsRegeneration = Prefs(struct {
|
||||
NoSNAT bool
|
||||
NetfilterMode router.NetfilterMode
|
||||
Persist *controlclient.Persist
|
||||
LogServer string
|
||||
}{})
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -388,13 +387,6 @@ func New(collection string) *Policy {
|
||||
HTTPC: &http.Client{Transport: newLogtailTransport(logtail.DefaultHost)},
|
||||
}
|
||||
|
||||
if val, ok := os.LookupEnv("TAILSCALE_LOG_TARGET"); ok {
|
||||
log.Println("You have enabled a non-default log target. Doing without being told to by Tailscale staff or your network administrator will make getting support difficult.")
|
||||
c.BaseURL = val
|
||||
u, _ := url.Parse(val)
|
||||
c.HTTPC = &http.Client{Transport: newLogtailTransport(u.Host)}
|
||||
}
|
||||
|
||||
filchBuf, filchErr := filch.New(filepath.Join(dir, cmdName), filch.Options{})
|
||||
if filchBuf != nil {
|
||||
c.Buffer = filchBuf
|
||||
|
||||
@@ -32,8 +32,7 @@ import (
|
||||
// 7: 2020-12-15: FilterRule.SrcIPs accepts CIDRs+ranges, doesn't warn about 0.0.0.0/::
|
||||
// 8: 2020-12-19: client can receive IPv6 addresses and routes if beta enabled server-side
|
||||
// 9: 2020-12-30: client doesn't auto-add implicit search domains from peers; only DNSConfig.Domains
|
||||
// 10: 2021-01-17: client understands MapResponse.PeerSeenChange
|
||||
const CurrentMapRequestVersion = 10
|
||||
const CurrentMapRequestVersion = 9
|
||||
|
||||
type ID int64
|
||||
|
||||
@@ -637,11 +636,6 @@ type MapResponse struct {
|
||||
// PeersRemoved are the NodeIDs that are no longer in the peer list.
|
||||
PeersRemoved []NodeID `json:",omitempty"`
|
||||
|
||||
// PeerSeenChange contains information on how to update peers' LastSeen
|
||||
// times. If the value is false, the peer is gone. If the value is true,
|
||||
// the LastSeen time is now. Absent means unchanged.
|
||||
PeerSeenChange map[NodeID]bool `json:",omitempty"`
|
||||
|
||||
// DNS is the same as DNSConfig.Nameservers.
|
||||
//
|
||||
// TODO(dmytro): should be sent in DNSConfig.Nameservers once clients have updated.
|
||||
|
||||
@@ -132,7 +132,7 @@ func RateLimitedFn(logf Logf, f time.Duration, burst int, maxCache int) Logf {
|
||||
logf(format, args...)
|
||||
case warn:
|
||||
// For the warning, log the specific format string
|
||||
logf("[RATE LIMITED] format string \"%s\" (example: \"%s\")", format, strings.TrimSpace(fmt.Sprintf(format, args...)))
|
||||
logf("[RATE LIMITED] format string \"%s\" (example: \"%s\")", format, fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +438,8 @@ func (a *addrSet) DstToBytes() []byte {
|
||||
return packIPPort(a.dst())
|
||||
}
|
||||
func (a *addrSet) DstToString() string {
|
||||
return a.Addrs()
|
||||
dst := a.dst()
|
||||
return dst.String()
|
||||
}
|
||||
func (a *addrSet) DstIP() net.IP {
|
||||
return a.dst().IP.IPAddr().IP // TODO: add netaddr accessor to cut an alloc here?
|
||||
|
||||
@@ -161,11 +161,6 @@ type Conn struct {
|
||||
// whether a DERP channel read should be done.
|
||||
derpRecvCountLast int64 // owned by ReceiveIPv4
|
||||
|
||||
// ippEndpoint4 and ippEndpoint6 are owned by ReceiveIPv4 and
|
||||
// ReceiveIPv6, respectively, to cache an IPPort->endpoint for
|
||||
// hot flows.
|
||||
ippEndpoint4, ippEndpoint6 ippEndpointCache
|
||||
|
||||
// ============================================================
|
||||
mu sync.Mutex // guards all following fields; see userspaceEngine lock ordering rules
|
||||
muCond *sync.Cond
|
||||
@@ -173,15 +168,6 @@ type Conn struct {
|
||||
started bool // Start was called
|
||||
closed bool // Close was called
|
||||
|
||||
// derpCleanupTimer is the timer that fires to occasionally clean
|
||||
// up idle DERP connections. It's only used when there is a non-home
|
||||
// DERP connection in use.
|
||||
derpCleanupTimer *time.Timer
|
||||
|
||||
// derpCleanupTimerArmed is whether derpCleanupTimer is
|
||||
// scheduled to fire within derpCleanStaleInterval.
|
||||
derpCleanupTimerArmed bool
|
||||
|
||||
// endpointsUpdateActive indicates that updateEndpoints is
|
||||
// currently running. It's used to deduplicate concurrent endpoint
|
||||
// update requests.
|
||||
@@ -497,6 +483,7 @@ func (c *Conn) Start() {
|
||||
if !version.IsMobile() {
|
||||
go c.periodicReSTUN()
|
||||
}
|
||||
go c.periodicDerpCleanup()
|
||||
}
|
||||
|
||||
// ignoreSTUNPackets sets a STUN packet processing func that does nothing.
|
||||
@@ -1227,7 +1214,6 @@ func (c *Conn) derpWriteChanOfAddr(addr netaddr.IPPort, peer key.Public) chan<-
|
||||
c.activeDerp[regionID] = ad
|
||||
c.logActiveDerpLocked()
|
||||
c.setPeerLastDerpLocked(peer, regionID, regionID)
|
||||
c.scheduleCleanStaleDerpLocked()
|
||||
|
||||
// Build a startGate for the derp reader+writer
|
||||
// goroutines, so they don't start running until any
|
||||
@@ -1497,7 +1483,7 @@ func (c *Conn) ReceiveIPv6(b []byte) (int, conn.Endpoint, error) {
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if ep, ok := c.receiveIP(b[:n], pAddr.(*net.UDPAddr), &c.ippEndpoint6); ok {
|
||||
if ep, ok := c.receiveIP(b[:n], pAddr.(*net.UDPAddr)); ok {
|
||||
return n, ep, nil
|
||||
}
|
||||
}
|
||||
@@ -1534,37 +1520,28 @@ func (c *Conn) ReceiveIPv4(b []byte) (n int, ep conn.Endpoint, err error) {
|
||||
}
|
||||
return 0, nil, err
|
||||
}
|
||||
if ep, ok := c.receiveIP(b[:n], pAddr.(*net.UDPAddr), &c.ippEndpoint4); ok {
|
||||
if ep, ok := c.receiveIP(b[:n], pAddr.(*net.UDPAddr)); ok {
|
||||
return n, ep, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// receiveIP is the shared bits of ReceiveIPv4 and ReceiveIPv6.
|
||||
func (c *Conn) receiveIP(b []byte, ua *net.UDPAddr, cache *ippEndpointCache) (ep conn.Endpoint, ok bool) {
|
||||
func (c *Conn) receiveIP(b []byte, ua *net.UDPAddr) (ep conn.Endpoint, ok bool) {
|
||||
ipp, ok := netaddr.FromStdAddr(ua.IP, ua.Port, ua.Zone)
|
||||
if !ok {
|
||||
return nil, false
|
||||
return
|
||||
}
|
||||
if stun.Is(b) {
|
||||
c.stunReceiveFunc.Load().(func([]byte, netaddr.IPPort))(b, ipp)
|
||||
return nil, false
|
||||
return
|
||||
}
|
||||
if c.handleDiscoMessage(b, ipp) {
|
||||
return nil, false
|
||||
return
|
||||
}
|
||||
if cache.ipp == ipp && cache.de != nil && cache.gen == cache.de.numStopAndReset() {
|
||||
ep = cache.de
|
||||
} else {
|
||||
ep = c.findEndpoint(ipp, ua, b)
|
||||
if ep == nil {
|
||||
return nil, false
|
||||
}
|
||||
if de, ok := ep.(*discoEndpoint); ok {
|
||||
cache.ipp = ipp
|
||||
cache.de = de
|
||||
cache.gen = de.numStopAndReset()
|
||||
}
|
||||
ep = c.findEndpoint(ipp, ua, b)
|
||||
if ep == nil {
|
||||
return
|
||||
}
|
||||
c.noteRecvActivityFromEndpoint(ep)
|
||||
return ep, true
|
||||
@@ -1631,7 +1608,7 @@ func (c *Conn) receiveIPv4DERP(b []byte) (n int, ep conn.Endpoint, err error) {
|
||||
c.mu.Lock()
|
||||
|
||||
discoEp = c.endpointOfDisco[dk]
|
||||
c.logf("magicsock: DERP packet received from idle peer %v; created=%v", dm.src.ShortString(), discoEp != nil)
|
||||
c.logf("magicsock: DERP packet received from idle peer %v; created=%v", dm.src.ShortString(), ep != nil)
|
||||
}
|
||||
}
|
||||
if !c.disableLegacy {
|
||||
@@ -1843,7 +1820,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort) bool {
|
||||
return true
|
||||
}
|
||||
de.handlePongConnLocked(dm, src)
|
||||
case *disco.CallMeMaybe:
|
||||
case disco.CallMeMaybe:
|
||||
if src.IP != derpMagicIPAddr {
|
||||
// CallMeMaybe messages should only come via DERP.
|
||||
c.logf("[unexpected] CallMeMaybe packets should only come via DERP")
|
||||
@@ -1851,7 +1828,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort) bool {
|
||||
}
|
||||
if de != nil {
|
||||
c.logf("magicsock: disco: %v<-%v (%v, %v) got call-me-maybe", c.discoShort, de.discoShort, de.publicKey.ShortString(), derpStr(src.String()))
|
||||
go de.handleCallMeMaybe(dm)
|
||||
go de.handleCallMeMaybe()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1882,29 +1859,6 @@ func (c *Conn) handlePingLocked(dm *disco.Ping, de *discoEndpoint, src netaddr.I
|
||||
}, discoVerboseLog)
|
||||
}
|
||||
|
||||
// enqueueCallMeMaybe schedules a send of disco.CallMeMaybe to de via derpAddr
|
||||
// once we know that our STUN endpoint is fresh.
|
||||
//
|
||||
// derpAddr is de.derpAddr at the time of send. It's assumed the peer won't be
|
||||
// flipping primary DERPs in the 0-30ms it takes to confirm our STUN endpoint.
|
||||
// If they do, traffic will just go over DERP for a bit longer until the next
|
||||
// discovery round.
|
||||
func (c *Conn) enqueueCallMeMaybe(derpAddr netaddr.IPPort, de *discoEndpoint) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
// TODO(bradfitz): do a fast/lite re-STUN if our STUN info is too old
|
||||
// Currently there's no "queue" despite the method name. There will be.
|
||||
|
||||
eps := make([]netaddr.IPPort, 0, len(c.lastEndpoints))
|
||||
for _, ep := range c.lastEndpoints {
|
||||
if ipp, err := netaddr.ParseIPPort(ep); err == nil {
|
||||
eps = append(eps, ipp)
|
||||
}
|
||||
}
|
||||
go de.sendDiscoMessage(derpAddr, &disco.CallMeMaybe{MyNumber: eps}, discoLog)
|
||||
}
|
||||
|
||||
// setAddrToDiscoLocked records that newk is at src.
|
||||
//
|
||||
// c.mu must be held.
|
||||
@@ -2231,14 +2185,9 @@ func (c *Conn) foreachActiveDerpSortedLocked(fn func(regionID int, ad activeDerp
|
||||
func (c *Conn) cleanStaleDerp() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.closed {
|
||||
return
|
||||
}
|
||||
c.derpCleanupTimerArmed = false
|
||||
|
||||
tooOld := time.Now().Add(-derpInactiveCleanupTime)
|
||||
const inactivityTime = 60 * time.Second
|
||||
tooOld := time.Now().Add(-inactivityTime)
|
||||
dirty := false
|
||||
someNonHomeOpen := false
|
||||
for i, ad := range c.activeDerp {
|
||||
if i == c.myDerp {
|
||||
continue
|
||||
@@ -2246,31 +2195,11 @@ func (c *Conn) cleanStaleDerp() {
|
||||
if ad.lastWrite.Before(tooOld) {
|
||||
c.closeDerpLocked(i, "idle")
|
||||
dirty = true
|
||||
} else {
|
||||
someNonHomeOpen = true
|
||||
}
|
||||
}
|
||||
if dirty {
|
||||
c.logActiveDerpLocked()
|
||||
}
|
||||
if someNonHomeOpen {
|
||||
c.scheduleCleanStaleDerpLocked()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) scheduleCleanStaleDerpLocked() {
|
||||
if c.derpCleanupTimerArmed {
|
||||
// Already going to fire soon. Let the existing one
|
||||
// fire lest it get infinitely delayed by repeated
|
||||
// calls to scheduleCleanStaleDerpLocked.
|
||||
return
|
||||
}
|
||||
c.derpCleanupTimerArmed = true
|
||||
if c.derpCleanupTimer != nil {
|
||||
c.derpCleanupTimer.Reset(derpCleanStaleInterval)
|
||||
} else {
|
||||
c.derpCleanupTimer = time.AfterFunc(derpCleanStaleInterval, c.cleanStaleDerp)
|
||||
}
|
||||
}
|
||||
|
||||
// DERPs reports the number of active DERP connections.
|
||||
@@ -2293,9 +2222,6 @@ func (c *Conn) Close() error {
|
||||
if c.closed {
|
||||
return nil
|
||||
}
|
||||
if c.derpCleanupTimerArmed {
|
||||
c.derpCleanupTimer.Stop()
|
||||
}
|
||||
|
||||
for _, ep := range c.endpointOfDisco {
|
||||
ep.stopAndReset()
|
||||
@@ -2319,6 +2245,13 @@ func (c *Conn) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// isClosed reports whether c is closed.
|
||||
func (c *Conn) isClosed() bool {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return c.closed
|
||||
}
|
||||
|
||||
func (c *Conn) goroutinesRunningLocked() bool {
|
||||
if c.endpointsUpdateActive {
|
||||
return true
|
||||
@@ -2411,6 +2344,19 @@ func (c *Conn) periodicReSTUN() {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) periodicDerpCleanup() {
|
||||
ticker := time.NewTicker(15 * time.Second) // arbitrary
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-c.donec:
|
||||
return
|
||||
case <-ticker.C:
|
||||
c.cleanStaleDerp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReSTUN triggers an address discovery.
|
||||
// The provided why string is for debug logging only.
|
||||
func (c *Conn) ReSTUN(why string) {
|
||||
@@ -2835,8 +2781,7 @@ func udpAddrDebugString(ua net.UDPAddr) string {
|
||||
// advertise a DiscoKey and participate in active discovery.
|
||||
type discoEndpoint struct {
|
||||
// atomically accessed; declared first for alignment reasons
|
||||
lastRecvUnixAtomic int64
|
||||
numStopAndResetAtomic int64
|
||||
lastRecvUnixAtomic int64
|
||||
|
||||
// These fields are initialized once and never modified.
|
||||
c *Conn
|
||||
@@ -2864,7 +2809,6 @@ type discoEndpoint struct {
|
||||
trustBestAddrUntil time.Time // time when bestAddr expires
|
||||
sentPing map[stun.TxID]sentPing
|
||||
endpointState map[netaddr.IPPort]*endpointState
|
||||
isCallMeMaybeEP map[netaddr.IPPort]bool
|
||||
|
||||
pendingCLIPings []pendingCLIPing // any outstanding "tailscale ping" commands running
|
||||
}
|
||||
@@ -2904,14 +2848,6 @@ const (
|
||||
// goodEnoughLatency is the latency at or under which we don't
|
||||
// try to upgrade to a better path.
|
||||
goodEnoughLatency = 5 * time.Millisecond
|
||||
|
||||
// derpInactiveCleanupTime is how long a non-home DERP connection
|
||||
// needs to be idle (last written to) before we close it.
|
||||
derpInactiveCleanupTime = 60 * time.Second
|
||||
|
||||
// derpCleanStaleInterval is how often cleanStaleDerp runs when there
|
||||
// are potentially-stale DERP connections to close.
|
||||
derpCleanStaleInterval = 15 * time.Second
|
||||
)
|
||||
|
||||
// endpointState is some state and history for a specific endpoint of
|
||||
@@ -2929,10 +2865,6 @@ type endpointState struct {
|
||||
// updated and use it to discard old candidates.
|
||||
lastGotPing time.Time
|
||||
|
||||
// callMeMaybeTime, if non-zero, is the time this endpoint
|
||||
// was advertised last via a call-me-maybe disco message.
|
||||
callMeMaybeTime time.Time
|
||||
|
||||
recentPongs []pongReply // ring buffer up to pongHistoryCount entries
|
||||
recentPong uint16 // index into recentPongs of most recent; older before, wrapped
|
||||
|
||||
@@ -2946,13 +2878,11 @@ const indexSentinelDeleted = -1
|
||||
// shouldDeleteLocked reports whether we should delete this endpoint.
|
||||
func (st *endpointState) shouldDeleteLocked() bool {
|
||||
switch {
|
||||
case !st.callMeMaybeTime.IsZero():
|
||||
return false
|
||||
case st.lastGotPing.IsZero():
|
||||
// This was an endpoint from the network map. Is it still in the network map?
|
||||
return st.index == indexSentinelDeleted
|
||||
default:
|
||||
// This was an endpoint discovered at runtime.
|
||||
// Thiw was an endpoint discovered at runtime.
|
||||
return time.Since(st.lastGotPing) > sessionActiveTimeout
|
||||
}
|
||||
}
|
||||
@@ -3052,6 +2982,10 @@ func (de *discoEndpoint) heartbeat() {
|
||||
|
||||
de.heartBeatTimer = nil
|
||||
|
||||
if de.c.isClosed() {
|
||||
return
|
||||
}
|
||||
|
||||
if de.lastSend.IsZero() {
|
||||
// Shouldn't happen.
|
||||
return
|
||||
@@ -3266,12 +3200,13 @@ func (de *discoEndpoint) sendPingsLocked(now time.Time, sendCallMeMaybe bool) {
|
||||
}
|
||||
derpAddr := de.derpAddr
|
||||
if sentAny && sendCallMeMaybe && !derpAddr.IsZero() {
|
||||
// Have our magicsock.Conn figure out its STUN endpoint (if
|
||||
// it doesn't know already) and then send a CallMeMaybe
|
||||
// message to our peer via DERP informing them that we've
|
||||
// sent so our firewall ports are probably open and now
|
||||
// would be a good time for them to connect.
|
||||
go de.c.enqueueCallMeMaybe(derpAddr, de)
|
||||
// In just a bit of a time (for goroutines above to schedule and run),
|
||||
// send a message to peer via DERP informing them that we've sent
|
||||
// so our firewall ports are probably open and now would be a good time
|
||||
// for them to connect.
|
||||
time.AfterFunc(5*time.Millisecond, func() {
|
||||
de.sendDiscoMessage(derpAddr, disco.CallMeMaybe{}, discoLog)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3453,34 +3388,10 @@ func (st *endpointState) addPongReplyLocked(r pongReply) {
|
||||
// DERP. The contract for use of this message is that the peer has
|
||||
// already sent to us via UDP, so their stateful firewall should be
|
||||
// open. Now we can Ping back and make it through.
|
||||
func (de *discoEndpoint) handleCallMeMaybe(m *disco.CallMeMaybe) {
|
||||
func (de *discoEndpoint) handleCallMeMaybe() {
|
||||
de.mu.Lock()
|
||||
defer de.mu.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
for ep := range de.isCallMeMaybeEP {
|
||||
de.isCallMeMaybeEP[ep] = false // mark for deletion
|
||||
}
|
||||
if de.isCallMeMaybeEP == nil {
|
||||
de.isCallMeMaybeEP = map[netaddr.IPPort]bool{}
|
||||
}
|
||||
for _, ep := range m.MyNumber {
|
||||
de.isCallMeMaybeEP[ep] = true
|
||||
if es, ok := de.endpointState[ep]; ok {
|
||||
es.callMeMaybeTime = now
|
||||
} else {
|
||||
de.endpointState[ep] = &endpointState{callMeMaybeTime: now}
|
||||
}
|
||||
}
|
||||
// Delete any prior CalllMeMaybe endpoints that weren't included
|
||||
// in this message.
|
||||
for ep, want := range de.isCallMeMaybeEP {
|
||||
if !want {
|
||||
delete(de.isCallMeMaybeEP, ep)
|
||||
de.deleteEndpointLocked(ep)
|
||||
}
|
||||
}
|
||||
|
||||
// Zero out all the lastPing times to force sendPingsLocked to send new ones,
|
||||
// even if it's been less than 5 seconds ago.
|
||||
for _, st := range de.endpointState {
|
||||
@@ -3509,7 +3420,6 @@ func (de *discoEndpoint) populatePeerStatus(ps *ipnstate.PeerStatus) {
|
||||
// It's called when a discovery endpoint is no longer present in the NetworkMap,
|
||||
// or when magicsock is transition from running to stopped state (via SetPrivateKey(zero))
|
||||
func (de *discoEndpoint) stopAndReset() {
|
||||
atomic.AddInt64(&de.numStopAndResetAtomic, 1)
|
||||
de.mu.Lock()
|
||||
defer de.mu.Unlock()
|
||||
|
||||
@@ -3537,10 +3447,6 @@ func (de *discoEndpoint) stopAndReset() {
|
||||
de.pendingCLIPings = nil
|
||||
}
|
||||
|
||||
func (de *discoEndpoint) numStopAndReset() int64 {
|
||||
return atomic.LoadInt64(&de.numStopAndResetAtomic)
|
||||
}
|
||||
|
||||
// derpStr replaces DERP IPs in s with "derp-".
|
||||
func derpStr(s string) string { return strings.ReplaceAll(s, "127.3.3.40:", "derp-") }
|
||||
|
||||
@@ -3562,11 +3468,3 @@ func (c *Conn) WhoIs(ip netaddr.IP) (n *tailcfg.Node, u tailcfg.UserProfile, ok
|
||||
}
|
||||
return nil, u, false
|
||||
}
|
||||
|
||||
// ippEndpointCache is a mutex-free single-element cache, mapping from
|
||||
// a single netaddr.IPPort to a single endpoint.
|
||||
type ippEndpointCache struct {
|
||||
ipp netaddr.IPPort
|
||||
gen int64
|
||||
de *discoEndpoint
|
||||
}
|
||||
|
||||
@@ -896,10 +896,7 @@ func testTwoDevicePing(t *testing.T, d *devices) {
|
||||
|
||||
// This gets reassigned inside every test, so that the connections
|
||||
// all log using the "current" t.Logf function. Sigh.
|
||||
nestedLogf, setT := makeNestable(t)
|
||||
|
||||
logf, closeLogf := logger.LogfCloser(nestedLogf)
|
||||
defer closeLogf()
|
||||
logf, setT := makeNestable(t)
|
||||
|
||||
derpMap, cleanup := runDERPAndStun(t, logf, d.stun, d.stunIP)
|
||||
defer cleanup()
|
||||
|
||||
Reference in New Issue
Block a user