summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@tailscale.com>2025-01-12 17:00:27 -0800
committerBrad Fitzpatrick <bradfitz@tailscale.com>2025-01-12 17:00:27 -0800
commitbc78993f8dea105a3587224e1e9bb115472217cf (patch)
treea28b1167c8cf8342fc407dcd3f23d0a8ff88c1df
parent31a27242456b583172fc35ce744fb542bc9a311e (diff)
downloadtailscale-bradfitz/lanscaping.tar.xz
tailscale-bradfitz/lanscaping.zip
lanscaping: remove TSMPbradfitz/lanscaping
-rwxr-xr-x@ 1 bradfitz staff 9752834 Jan 12 16:59 /Users/bradfitz/bin/tailscaled.min -rwxr-xr-x@ 1 bradfitz staff 9633944 Jan 12 16:59 /Users/bradfitz/bin/tailscaled.minlinux Change-Id: I12db5d0f2b90aae55709eed4751cc342d59b43cd Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
-rw-r--r--cmd/tailscale/depaware-minlinux.txt1
-rw-r--r--cmd/tailscaled/depaware-minlinux.txt2
-rw-r--r--net/packet/packet.go8
-rw-r--r--net/packet/tsmp.go264
-rw-r--r--net/tstun/wrap.go26
-rw-r--r--types/ipproto/ipproto.go14
-rw-r--r--wgengine/filter/filter.go4
-rw-r--r--wgengine/pendopen.go228
-rw-r--r--wgengine/userspace.go93
9 files changed, 6 insertions, 634 deletions
diff --git a/cmd/tailscale/depaware-minlinux.txt b/cmd/tailscale/depaware-minlinux.txt
index a8f62babe..00c8048c7 100644
--- a/cmd/tailscale/depaware-minlinux.txt
+++ b/cmd/tailscale/depaware-minlinux.txt
@@ -51,7 +51,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/ipn from tailscale.com/client/tailscale+
tailscale.com/ipn/ipnstate from tailscale.com/client/tailscale+
tailscale.com/licenses from tailscale.com/client/web+
- tailscale.com/net/flowtrack from tailscale.com/net/packet
tailscale.com/net/netaddr from tailscale.com/ipn+
tailscale.com/net/netcheck from tailscale.com/cmd/tailscale/cli
tailscale.com/net/neterror from tailscale.com/net/netcheck+
diff --git a/cmd/tailscaled/depaware-minlinux.txt b/cmd/tailscaled/depaware-minlinux.txt
index 2f30e4f01..19bbb06d3 100644
--- a/cmd/tailscaled/depaware-minlinux.txt
+++ b/cmd/tailscaled/depaware-minlinux.txt
@@ -44,7 +44,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/ipn/store from tailscale.com/cmd/tailscaled
tailscale.com/ipn/store/mem from tailscale.com/ipn/store
tailscale.com/logtail/backoff from tailscale.com/control/controlclient+
- tailscale.com/net/flowtrack from tailscale.com/net/packet+
+ tailscale.com/net/flowtrack from tailscale.com/wgengine/filter
tailscale.com/net/ipset from tailscale.com/ipn/ipnlocal+
tailscale.com/net/netaddr from tailscale.com/ipn+
tailscale.com/net/netcheck from tailscale.com/wgengine/magicsock
diff --git a/net/packet/packet.go b/net/packet/packet.go
index c9521ad46..76557cd0d 100644
--- a/net/packet/packet.go
+++ b/net/packet/packet.go
@@ -218,10 +218,6 @@ func (q *Parsed) decode4(b []byte) {
q.Src = withPort(q.Src, binary.BigEndian.Uint16(sub[0:2]))
q.Dst = withPort(q.Dst, binary.BigEndian.Uint16(sub[2:4]))
return
- case ipproto.TSMP:
- // Inter-tailscale messages.
- q.dataofs = q.subofs
- return
case ipproto.Fragment:
// An IPProto value of 0xff (our Fragment constant for internal use)
// should never actually be used in the wild; if we see it,
@@ -321,10 +317,6 @@ func (q *Parsed) decode6(b []byte) {
q.Src = withPort(q.Src, binary.BigEndian.Uint16(sub[0:2]))
q.Dst = withPort(q.Dst, binary.BigEndian.Uint16(sub[2:4]))
return
- case ipproto.TSMP:
- // Inter-tailscale messages.
- q.dataofs = q.subofs
- return
case ipproto.Fragment:
// An IPProto value of 0xff (our Fragment constant for internal use)
// should never actually be used in the wild; if we see it,
diff --git a/net/packet/tsmp.go b/net/packet/tsmp.go
deleted file mode 100644
index 4e004cca2..000000000
--- a/net/packet/tsmp.go
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-// TSMP is our ICMP-like "Tailscale Message Protocol" for signaling
-// Tailscale-specific messages between nodes. It uses IP protocol 99
-// (reserved for "any private encryption scheme") within
-// WireGuard's normal encryption between peers and never hits the host
-// network stack.
-
-package packet
-
-import (
- "encoding/binary"
- "errors"
- "fmt"
- "net/netip"
-
- "tailscale.com/net/flowtrack"
- "tailscale.com/types/ipproto"
-)
-
-// TailscaleRejectedHeader is a TSMP message that says that one
-// Tailscale node has rejected the connection from another. Unlike a
-// TCP RST, this includes a reason.
-//
-// On the wire, after the IP header, it's currently 7 or 8 bytes:
-// - '!'
-// - IPProto byte (IANA protocol number: TCP or UDP)
-// - 'A' or 'S' (RejectedDueToACLs, RejectedDueToShieldsUp)
-// - srcPort big endian uint16
-// - dstPort big endian uint16
-// - [optional] byte of flag bits:
-// lowest bit (0x1): MaybeBroken
-//
-// In the future it might also accept 16 byte IP flow src/dst IPs
-// after the header, if they're different than the IP-level ones.
-type TailscaleRejectedHeader struct {
- IPSrc netip.Addr // IPv4 or IPv6 header's src IP
- IPDst netip.Addr // IPv4 or IPv6 header's dst IP
- Src netip.AddrPort // rejected flow's src
- Dst netip.AddrPort // rejected flow's dst
- Proto ipproto.Proto // proto that was rejected (TCP or UDP)
- Reason TailscaleRejectReason // why the connection was rejected
-
- // MaybeBroken is whether the rejection is non-terminal (the
- // client should not fail immediately). This is sent by a
- // target when it's not sure whether it's totally broken, but
- // it might be. For example, the target tailscaled might think
- // its host firewall or IP forwarding aren't configured
- // properly, but tailscaled might be wrong (not having enough
- // visibility into what the OS is doing). When true, the
- // message is simply an FYI as a potential reason to use for
- // later when the pendopen connection tracking timer expires.
- MaybeBroken bool
-}
-
-const rejectFlagBitMaybeBroken = 0x1
-
-func (rh TailscaleRejectedHeader) Flow() flowtrack.Tuple {
- return flowtrack.MakeTuple(rh.Proto, rh.Src, rh.Dst)
-}
-
-func (rh TailscaleRejectedHeader) String() string {
- return fmt.Sprintf("TSMP-reject-flow{%s %s > %s}: %s", rh.Proto, rh.Src, rh.Dst, rh.Reason)
-}
-
-type TSMPType uint8
-
-const (
- // TSMPTypeRejectedConn is the type byte for a TailscaleRejectedHeader.
- TSMPTypeRejectedConn TSMPType = '!'
-
- // TSMPTypePing is the type byte for a TailscalePingRequest.
- TSMPTypePing TSMPType = 'p'
-
- // TSMPTypePong is the type byte for a TailscalePongResponse.
- TSMPTypePong TSMPType = 'o'
-)
-
-type TailscaleRejectReason byte
-
-// IsZero reports whether r is the zero value, representing no rejection.
-func (r TailscaleRejectReason) IsZero() bool { return r == TailscaleRejectReasonNone }
-
-const (
- // TailscaleRejectReasonNone is the TailscaleRejectReason zero value.
- TailscaleRejectReasonNone TailscaleRejectReason = 0
-
- // RejectedDueToACLs means that the host rejected the connection due to ACLs.
- RejectedDueToACLs TailscaleRejectReason = 'A'
-
- // RejectedDueToShieldsUp means that the host rejected the connection due to shields being up.
- RejectedDueToShieldsUp TailscaleRejectReason = 'S'
-
- // RejectedDueToIPForwarding means that the relay node's IP
- // forwarding is disabled.
- RejectedDueToIPForwarding TailscaleRejectReason = 'F'
-
- // RejectedDueToHostFirewall means that the target host's
- // firewall is blocking the traffic.
- RejectedDueToHostFirewall TailscaleRejectReason = 'W'
-)
-
-func (r TailscaleRejectReason) String() string {
- switch r {
- case RejectedDueToACLs:
- return "acl"
- case RejectedDueToShieldsUp:
- return "shields"
- case RejectedDueToIPForwarding:
- return "host-ip-forwarding-unavailable"
- case RejectedDueToHostFirewall:
- return "host-firewall"
- }
- return fmt.Sprintf("0x%02x", byte(r))
-}
-
-func (h TailscaleRejectedHeader) hasFlags() bool {
- return h.MaybeBroken // the only one currently
-}
-
-func (h TailscaleRejectedHeader) Len() int {
- v := 1 + // TSMPType byte
- 1 + // IPProto byte
- 1 + // TailscaleRejectReason byte
- 2*2 // 2 uint16 ports
- if h.IPSrc.Is4() {
- v += ip4HeaderLength
- } else if h.IPSrc.Is6() {
- v += ip6HeaderLength
- }
- if h.hasFlags() {
- v++
- }
- return v
-}
-
-func (h TailscaleRejectedHeader) Marshal(buf []byte) error {
- if len(buf) < h.Len() {
- return errSmallBuffer
- }
- if len(buf) > maxPacketLength {
- return errLargePacket
- }
- if h.Src.Addr().Is4() {
- iph := IP4Header{
- IPProto: ipproto.TSMP,
- Src: h.IPSrc,
- Dst: h.IPDst,
- }
- iph.Marshal(buf)
- buf = buf[ip4HeaderLength:]
- } else if h.Src.Addr().Is6() {
- iph := IP6Header{
- IPProto: ipproto.TSMP,
- Src: h.IPSrc,
- Dst: h.IPDst,
- }
- iph.Marshal(buf)
- buf = buf[ip6HeaderLength:]
- } else {
- return errors.New("bogus src IP")
- }
- buf[0] = byte(TSMPTypeRejectedConn)
- buf[1] = byte(h.Proto)
- buf[2] = byte(h.Reason)
- binary.BigEndian.PutUint16(buf[3:5], h.Src.Port())
- binary.BigEndian.PutUint16(buf[5:7], h.Dst.Port())
-
- if h.hasFlags() {
- var flags byte
- if h.MaybeBroken {
- flags |= rejectFlagBitMaybeBroken
- }
- buf[7] = flags
- }
- return nil
-}
-
-// AsTailscaleRejectedHeader parses pp as an incoming rejection
-// connection TSMP message.
-//
-// ok reports whether pp was a valid TSMP rejection packet.
-func (pp *Parsed) AsTailscaleRejectedHeader() (h TailscaleRejectedHeader, ok bool) {
- p := pp.Payload()
- if len(p) < 7 || p[0] != byte(TSMPTypeRejectedConn) {
- return
- }
- h = TailscaleRejectedHeader{
- Proto: ipproto.Proto(p[1]),
- Reason: TailscaleRejectReason(p[2]),
- IPSrc: pp.Src.Addr(),
- IPDst: pp.Dst.Addr(),
- Src: netip.AddrPortFrom(pp.Dst.Addr(), binary.BigEndian.Uint16(p[3:5])),
- Dst: netip.AddrPortFrom(pp.Src.Addr(), binary.BigEndian.Uint16(p[5:7])),
- }
- if len(p) > 7 {
- flags := p[7]
- h.MaybeBroken = (flags & rejectFlagBitMaybeBroken) != 0
- }
- return h, true
-}
-
-// TSMPPingRequest is a TSMP message that's like an ICMP ping request.
-//
-// On the wire, after the IP header, it's currently 9 bytes:
-// - 'p' (TSMPTypePing)
-// - 8 opaque ping bytes to copy back in the response
-type TSMPPingRequest struct {
- Data [8]byte
-}
-
-func (pp *Parsed) AsTSMPPing() (h TSMPPingRequest, ok bool) {
- if pp.IPProto != ipproto.TSMP {
- return
- }
- p := pp.Payload()
- if len(p) < 9 || p[0] != byte(TSMPTypePing) {
- return
- }
- copy(h.Data[:], p[1:])
- return h, true
-}
-
-type TSMPPongReply struct {
- IPHeader Header
- Data [8]byte
- PeerAPIPort uint16
-}
-
-// AsTSMPPong returns pp as a TSMPPongReply and whether it is one.
-// The pong.IPHeader field is not populated.
-func (pp *Parsed) AsTSMPPong() (pong TSMPPongReply, ok bool) {
- if pp.IPProto != ipproto.TSMP {
- return
- }
- p := pp.Payload()
- if len(p) < 9 || p[0] != byte(TSMPTypePong) {
- return
- }
- copy(pong.Data[:], p[1:])
- if len(p) >= 11 {
- pong.PeerAPIPort = binary.BigEndian.Uint16(p[9:])
- }
- return pong, true
-}
-
-func (h TSMPPongReply) Len() int {
- return h.IPHeader.Len() + 11
-}
-
-func (h TSMPPongReply) Marshal(buf []byte) error {
- if len(buf) < h.Len() {
- return errSmallBuffer
- }
- if err := h.IPHeader.Marshal(buf); err != nil {
- return err
- }
- buf = buf[h.IPHeader.Len():]
- buf[0] = byte(TSMPTypePong)
- copy(buf[1:], h.Data[:])
- binary.BigEndian.PutUint16(buf[9:11], h.PeerAPIPort)
- return nil
-}
diff --git a/net/tstun/wrap.go b/net/tstun/wrap.go
index b1b0b07b0..d65d0641c 100644
--- a/net/tstun/wrap.go
+++ b/net/tstun/wrap.go
@@ -164,9 +164,6 @@ type Wrapper struct {
// PostFilterPacketOutboundToWireGuard is the outbound filter function that runs after the main filter.
PostFilterPacketOutboundToWireGuard FilterFunc
- // OnTSMPPongReceived, if non-nil, is called whenever a TSMP pong arrives.
- OnTSMPPongReceived func(packet.TSMPPongReply)
-
// OnICMPEchoResponseReceived, if non-nil, is called whenever a ICMP echo response
// arrives. If the packet is to be handled internally this returns true,
// false otherwise.
@@ -916,29 +913,6 @@ func (t *Wrapper) InjectInboundDirect(buf []byte, offset int) error {
return err
}
-func (t *Wrapper) injectOutboundPong(pp *packet.Parsed, req packet.TSMPPingRequest) {
- pong := packet.TSMPPongReply{
- Data: req.Data,
- }
- if t.PeerAPIPort != nil {
- pong.PeerAPIPort, _ = t.PeerAPIPort(pp.Dst.Addr())
- }
- switch pp.IPVersion {
- case 4:
- h4 := pp.IP4Header()
- h4.ToResponse()
- pong.IPHeader = h4
- case 6:
- h6 := pp.IP6Header()
- h6.ToResponse()
- pong.IPHeader = h6
- default:
- return
- }
-
- t.InjectOutbound(packet.Generate(pong, nil))
-}
-
// InjectOutbound makes the Wrapper device behave as if a packet
// with the given contents was sent to the network.
// It does not block, but takes ownership of the packet.
diff --git a/types/ipproto/ipproto.go b/types/ipproto/ipproto.go
index cfb41dcd5..3858cb1b7 100644
--- a/types/ipproto/ipproto.go
+++ b/types/ipproto/ipproto.go
@@ -54,17 +54,6 @@ const (
GRE Proto = 0x2f
SCTP Proto = 0x84
- // TSMP is the Tailscale Message Protocol (our ICMP-ish
- // thing), an IP protocol used only between Tailscale nodes
- // (still encrypted by WireGuard) that communicates why things
- // failed, etc.
- //
- // Proto number 99 is reserved for "any private encryption
- // scheme". We never accept these from the host OS stack nor
- // send them to the host network stack. It's only used between
- // nodes.
- TSMP Proto = 99
-
// Fragment represents any non-first IP fragment, for which we
// don't have the sub-protocol header (and therefore can't
// figure out what the sub-protocol is).
@@ -93,8 +82,6 @@ func (p Proto) String() string {
return "TCP"
case SCTP:
return "SCTP"
- case TSMP:
- return "TSMP"
case GRE:
return "GRE"
case DCCP:
@@ -144,7 +131,6 @@ var (
"ipv6-icmp": ICMPv6,
"sctp": SCTP,
"tcp": TCP,
- "tsmp": TSMP,
"udp": UDP,
}
)
diff --git a/wgengine/filter/filter.go b/wgengine/filter/filter.go
index 9e5d8a37f..36cee12cd 100644
--- a/wgengine/filter/filter.go
+++ b/wgengine/filter/filter.go
@@ -503,8 +503,6 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
if f.matches4.match(q, f.srcIPHasCap) {
return Accept, "ok"
}
- case ipproto.TSMP:
- return Accept, "tsmp ok"
default:
if f.matches4.matchProtoAndIPsOnlyIfAllPorts(q) {
return Accept, "other-portless ok"
@@ -563,8 +561,6 @@ func (f *Filter) runIn6(q *packet.Parsed) (r Response, why string) {
if f.matches6.match(q, f.srcIPHasCap) {
return Accept, "ok"
}
- case ipproto.TSMP:
- return Accept, "tsmp ok"
default:
if f.matches6.matchProtoAndIPsOnlyIfAllPorts(q) {
return Accept, "other-portless ok"
diff --git a/wgengine/pendopen.go b/wgengine/pendopen.go
deleted file mode 100644
index c7c028d06..000000000
--- a/wgengine/pendopen.go
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-package wgengine
-
-import (
- "fmt"
- "net/netip"
- "time"
-
- "tailscale.com/net/flowtrack"
- "tailscale.com/net/packet"
- "tailscale.com/net/tstun"
- "tailscale.com/types/ipproto"
- "tailscale.com/util/mak"
- "tailscale.com/wgengine/filter"
-)
-
-const tcpTimeoutBeforeDebug = 5 * time.Second
-
-type pendingOpenFlow struct {
- timer *time.Timer // until giving up on the flow
-
- // guarded by userspaceEngine.mu:
-
- // problem is non-zero if we got a MaybeBroken (non-terminal)
- // TSMP "reject" header.
- problem packet.TailscaleRejectReason
-}
-
-func (e *userspaceEngine) removeFlow(f flowtrack.Tuple) (removed bool) {
- e.mu.Lock()
- defer e.mu.Unlock()
- of, ok := e.pendOpen[f]
- if !ok {
- // Not a tracked flow (likely already removed)
- return false
- }
- of.timer.Stop()
- delete(e.pendOpen, f)
- return true
-}
-
-func (e *userspaceEngine) noteFlowProblemFromPeer(f flowtrack.Tuple, problem packet.TailscaleRejectReason) {
- e.mu.Lock()
- defer e.mu.Unlock()
- of, ok := e.pendOpen[f]
- if !ok {
- // Not a tracked flow (likely already removed)
- return
- }
- of.problem = problem
-}
-
-func (e *userspaceEngine) trackOpenPreFilterIn(pp *packet.Parsed, t *tstun.Wrapper) (res filter.Response) {
- res = filter.Accept // always
-
- if pp.IPProto == ipproto.TSMP {
- res = filter.DropSilently
- rh, ok := pp.AsTailscaleRejectedHeader()
- if !ok {
- return
- }
- if rh.MaybeBroken {
- e.noteFlowProblemFromPeer(rh.Flow(), rh.Reason)
- } else if f := rh.Flow(); e.removeFlow(f) {
- e.logf("open-conn-track: flow %v %v > %v rejected due to %v", rh.Proto, rh.Src, rh.Dst, rh.Reason)
- }
- return
- }
-
- if pp.IPVersion == 0 ||
- pp.IPProto != ipproto.TCP ||
- pp.TCPFlags&(packet.TCPSyn|packet.TCPRst) == 0 {
- return
- }
-
- // Either a SYN or a RST came back. Remove it in either case.
-
- f := flowtrack.MakeTuple(pp.IPProto, pp.Dst, pp.Src) // src/dst reversed
- removed := e.removeFlow(f)
- if removed && pp.TCPFlags&packet.TCPRst != 0 {
- e.logf("open-conn-track: flow TCP %v got RST by peer", f)
- }
- return
-}
-
-// isOSNetworkProbe reports whether the target is likely a network
-// connectivity probe target from e.g. iOS or Ubuntu network-manager.
-//
-// iOS likes to probe Apple IPs on all interfaces to check for connectivity.
-// Don't start timers tracking those. They won't succeed anyway. Avoids log
-// spam like:
-func (e *userspaceEngine) isOSNetworkProbe(dst netip.AddrPort) bool {
-
- return false
-}
-
-func (e *userspaceEngine) trackOpenPostFilterOut(pp *packet.Parsed, t *tstun.Wrapper) (res filter.Response) {
- res = filter.Accept // always
-
- if pp.IPVersion == 0 ||
- pp.IPProto != ipproto.TCP ||
- pp.TCPFlags&packet.TCPAck != 0 ||
- pp.TCPFlags&packet.TCPSyn == 0 {
- return
- }
- if e.isOSNetworkProbe(pp.Dst) {
- return
- }
-
- flow := flowtrack.MakeTuple(pp.IPProto, pp.Src, pp.Dst)
-
- e.mu.Lock()
- defer e.mu.Unlock()
- if _, dup := e.pendOpen[flow]; dup {
- // Duplicates are expected when the OS retransmits. Ignore.
- return
- }
-
- timer := time.AfterFunc(tcpTimeoutBeforeDebug, func() {
- e.onOpenTimeout(flow)
- })
- mak.Set(&e.pendOpen, flow, &pendingOpenFlow{timer: timer})
-
- return filter.Accept
-}
-
-func (e *userspaceEngine) onOpenTimeout(flow flowtrack.Tuple) {
- e.mu.Lock()
- of, ok := e.pendOpen[flow]
- if !ok {
- // Not a tracked flow, or already handled & deleted.
- e.mu.Unlock()
- return
- }
- delete(e.pendOpen, flow)
- problem := of.problem
- e.mu.Unlock()
-
- if !problem.IsZero() {
- e.logf("open-conn-track: timeout opening %v; peer reported problem: %v", flow, problem)
- }
-
- // Diagnose why it might've timed out.
- pip, ok := e.PeerForIP(flow.DstAddr())
- if !ok {
- e.logf("open-conn-track: timeout opening %v; no associated peer node", flow)
- return
- }
- n := pip.Node
- if !n.IsWireGuardOnly() {
- if n.DiscoKey().IsZero() {
- e.logf("open-conn-track: timeout opening %v; peer node %v running pre-0.100", flow, n.Key().ShortString())
- return
- }
- if n.DERP() == "" {
- e.logf("open-conn-track: timeout opening %v; peer node %v not connected to any DERP relay", flow, n.Key().ShortString())
- return
- }
- }
-
- ps, found := e.getPeerStatusLite(n.Key())
- if !found {
- onlyZeroRoute := true // whether peerForIP returned n only because its /0 route matched
- for _, r := range n.AllowedIPs().All() {
- if r.Bits() != 0 && r.Contains(flow.DstAddr()) {
- onlyZeroRoute = false
- break
- }
- }
- if onlyZeroRoute {
- // This node was returned by peerForIP because
- // its exit node /0 route(s) matched, but this
- // might not be the exit node that's currently
- // selected. Rather than log misleading
- // errors, just don't log at all for now.
- // TODO(bradfitz): update this code to be
- // exit-node-aware and make peerForIP return
- // the node of the currently selected exit
- // node.
- return
- }
- e.logf("open-conn-track: timeout opening %v; target node %v in netmap but unknown to WireGuard", flow, n.Key().ShortString())
- return
- }
-
- // TODO(bradfitz): figure out what PeerStatus.LastHandshake
- // is. It appears to be the last time we sent a handshake,
- // which isn't what I expected. I thought it was when a
- // handshake completed, which is what I want.
- _ = ps.LastHandshake
-
- online := "?"
- if n.IsWireGuardOnly() {
- online = "wg"
- } else {
- if v := n.Online(); v != nil {
- if *v {
- online = "yes"
- } else {
- online = "no"
- }
- }
- if n.LastSeen() != nil && online != "yes" {
- online += fmt.Sprintf(", lastseen=%v", durFmt(*n.LastSeen()))
- }
- }
- e.logf("open-conn-track: timeout opening %v to node %v; online=%v, lastRecv=%v",
- flow, n.Key().ShortString(),
- online,
- e.magicConn.LastRecvActivityOfNodeKey(n.Key()))
-}
-
-func durFmt(t time.Time) string {
- if t.IsZero() {
- return "never"
- }
- d := time.Since(t).Round(time.Second)
- if d < 10*time.Minute {
- // node.LastSeen times are rounded very coarsely, and
- // we compare times from different clocks (server vs
- // local), so negative is common when close. Format as
- // "recent" if negative or actually recent.
- return "recent"
- }
- return d.String()
-}
diff --git a/wgengine/userspace.go b/wgengine/userspace.go
index cc37f5b0c..5d2896b86 100644
--- a/wgengine/userspace.go
+++ b/wgengine/userspace.go
@@ -5,7 +5,6 @@ package wgengine
import (
"bufio"
- crand "crypto/rand"
"errors"
"fmt"
"io"
@@ -22,7 +21,6 @@ import (
"tailscale.com/envknob"
"tailscale.com/health"
"tailscale.com/ipn/ipnstate"
- "tailscale.com/net/flowtrack"
"tailscale.com/net/ipset"
"tailscale.com/net/netmon"
"tailscale.com/net/packet"
@@ -123,11 +121,7 @@ type userspaceEngine struct {
statusCallback StatusCallback
peerSequence []key.NodePublic
endpoints []tailcfg.Endpoint
- pendOpen map[flowtrack.Tuple]*pendingOpenFlow // see pendopen.go
- // pongCallback is the map of response handlers waiting for disco or TSMP
- // pong callbacks. The map key is a random slice of bytes.
- pongCallback map[[8]byte]func(packet.TSMPPongReply)
// icmpEchoResponseCallback is the map of response handlers waiting for ICMP
// echo responses. The map key is a random uint32 that is the little endian
// value of the ICMP identifier and sequence number concatenated.
@@ -366,27 +360,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
}
e.tundev.PreFilterPacketOutboundToWireGuardEngineIntercept = e.handleLocalPackets
- if envknob.BoolDefaultTrue("TS_DEBUG_CONNECT_FAILURES") {
- if e.tundev.PreFilterPacketInboundFromWireGuard != nil {
- return nil, errors.New("unexpected PreFilterIn already set")
- }
- e.tundev.PreFilterPacketInboundFromWireGuard = e.trackOpenPreFilterIn
- if e.tundev.PostFilterPacketOutboundToWireGuard != nil {
- return nil, errors.New("unexpected PostFilterOut already set")
- }
- e.tundev.PostFilterPacketOutboundToWireGuard = e.trackOpenPostFilterOut
- }
-
e.wgLogger = wglog.NewLogger(logf)
- e.tundev.OnTSMPPongReceived = func(pong packet.TSMPPongReply) {
- e.mu.Lock()
- defer e.mu.Unlock()
- cb := e.pongCallback[pong.Data]
- e.logf("wgengine: got TSMP pong %02x, peerAPIPort=%v; cb=%v", pong.Data, pong.PeerAPIPort, cb != nil)
- if cb != nil {
- go cb(pong)
- }
- }
e.tundev.OnICMPEchoResponseReceived = func(p *packet.Parsed) bool {
idSeq := p.EchoIDSeq()
@@ -1111,14 +1085,17 @@ func (e *userspaceEngine) Ping(ip netip.Addr, pingType tailcfg.PingType, size in
cb(res)
return
}
+ if pingType == "TSMP" {
+ res.Err = "TSMP ping not supported"
+ cb(res)
+ return
+ }
peer := pip.Node
e.logf("ping(%v): sending %v ping to %v %v ...", ip, pingType, peer.Key().ShortString(), peer.ComputedName())
switch pingType {
case "disco":
e.magicConn.Ping(peer, res, size, cb)
- case "TSMP":
- e.sendTSMPPing(ip, peer, res, cb)
case "ICMP":
e.sendICMPEchoRequest(ip, peer, res, cb)
}
@@ -1192,66 +1169,6 @@ func (e *userspaceEngine) sendICMPEchoRequest(destIP netip.Addr, peer tailcfg.No
e.tundev.InjectOutbound(icmpPing)
}
-func (e *userspaceEngine) sendTSMPPing(ip netip.Addr, peer tailcfg.NodeView, res *ipnstate.PingResult, cb func(*ipnstate.PingResult)) {
- srcIP, err := e.mySelfIPMatchingFamily(ip)
- if err != nil {
- res.Err = err.Error()
- cb(res)
- return
- }
- var iph packet.Header
- if srcIP.Is4() {
- iph = packet.IP4Header{
- IPProto: ipproto.TSMP,
- Src: srcIP,
- Dst: ip,
- }
- } else {
- iph = packet.IP6Header{
- IPProto: ipproto.TSMP,
- Src: srcIP,
- Dst: ip,
- }
- }
-
- var data [8]byte
- crand.Read(data[:])
-
- expireTimer := time.AfterFunc(10*time.Second, func() {
- e.setTSMPPongCallback(data, nil)
- })
- t0 := time.Now()
- e.setTSMPPongCallback(data, func(pong packet.TSMPPongReply) {
- expireTimer.Stop()
- d := time.Since(t0)
- res.LatencySeconds = d.Seconds()
- res.NodeIP = ip.String()
- res.NodeName = peer.ComputedName()
- res.PeerAPIPort = pong.PeerAPIPort
- cb(res)
- })
-
- var tsmpPayload [9]byte
- tsmpPayload[0] = byte(packet.TSMPTypePing)
- copy(tsmpPayload[1:], data[:])
-
- tsmpPing := packet.Generate(iph, tsmpPayload[:])
- e.tundev.InjectOutbound(tsmpPing)
-}
-
-func (e *userspaceEngine) setTSMPPongCallback(data [8]byte, cb func(packet.TSMPPongReply)) {
- e.mu.Lock()
- defer e.mu.Unlock()
- if e.pongCallback == nil {
- e.pongCallback = map[[8]byte]func(packet.TSMPPongReply){}
- }
- if cb == nil {
- delete(e.pongCallback, data)
- } else {
- e.pongCallback[data] = cb
- }
-}
-
func (e *userspaceEngine) setICMPEchoResponseCallback(idSeq uint32, cb func()) {
e.mu.Lock()
defer e.mu.Unlock()