mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-19 05:02:34 +00:00
net/{packet,tstun}: send peerapi port in TSMP pongs
For discovery when an explicit hostname/IP is known. We'll still also send it via control for finding peers by a list. Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
9659ab81e0
commit
41e4e02e57
@ -143,7 +143,11 @@ func runPing(ctx context.Context, args []string) error {
|
|||||||
via = "TSMP"
|
via = "TSMP"
|
||||||
}
|
}
|
||||||
anyPong = true
|
anyPong = true
|
||||||
fmt.Printf("pong from %s (%s) via %v in %v\n", pr.NodeName, pr.NodeIP, via, latency)
|
extra := ""
|
||||||
|
if pr.PeerAPIPort != 0 {
|
||||||
|
extra = fmt.Sprintf(", %d", pr.PeerAPIPort)
|
||||||
|
}
|
||||||
|
fmt.Printf("pong from %s (%s%s) via %v in %v\n", pr.NodeName, pr.NodeIP, extra, via, latency)
|
||||||
if pingArgs.tsmp {
|
if pingArgs.tsmp {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,10 @@ func run() error {
|
|||||||
|
|
||||||
var ns *netstack.Impl
|
var ns *netstack.Impl
|
||||||
if useNetstack {
|
if useNetstack {
|
||||||
tunDev, magicConn := e.(wgengine.InternalsGetter).GetInternals()
|
tunDev, magicConn, ok := e.(wgengine.InternalsGetter).GetInternals()
|
||||||
|
if !ok {
|
||||||
|
log.Fatalf("%T is not a wgengine.InternalsGetter", e)
|
||||||
|
}
|
||||||
ns, err = netstack.Create(logf, tunDev, e, magicConn)
|
ns, err = netstack.Create(logf, tunDev, e, magicConn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("netstack.Create: %v", err)
|
log.Fatalf("netstack.Create: %v", err)
|
||||||
|
@ -155,6 +155,17 @@ func NewLocalBackend(logf logger.Logf, logid string, store ipn.StateStore, e wge
|
|||||||
|
|
||||||
b.unregisterHealthWatch = health.RegisterWatcher(b.onHealthChange)
|
b.unregisterHealthWatch = health.RegisterWatcher(b.onHealthChange)
|
||||||
|
|
||||||
|
wiredPeerAPIPort := false
|
||||||
|
if ig, ok := e.(wgengine.InternalsGetter); ok {
|
||||||
|
if tunWrap, _, ok := ig.GetInternals(); ok {
|
||||||
|
tunWrap.PeerAPIPort = b.getPeerAPIPortForTSMPPing
|
||||||
|
wiredPeerAPIPort = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !wiredPeerAPIPort {
|
||||||
|
b.logf("[unexpected] failed to wire up peer API port for engine %T", e)
|
||||||
|
}
|
||||||
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1330,6 +1341,17 @@ func (b *LocalBackend) SetPrefs(newp *ipn.Prefs) {
|
|||||||
b.send(ipn.Notify{Prefs: newp})
|
b.send(ipn.Notify{Prefs: newp})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *LocalBackend) getPeerAPIPortForTSMPPing(ip netaddr.IP) (port uint16, ok bool) {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
for _, pln := range b.peerAPIListeners {
|
||||||
|
if pln.ip.BitLen() == ip.BitLen() {
|
||||||
|
return uint16(pln.Port()), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) peerAPIServicesLocked() (ret []tailcfg.Service) {
|
func (b *LocalBackend) peerAPIServicesLocked() (ret []tailcfg.Service) {
|
||||||
for _, pln := range b.peerAPIListeners {
|
for _, pln := range b.peerAPIListeners {
|
||||||
proto := tailcfg.ServiceProto("peerapi4")
|
proto := tailcfg.ServiceProto("peerapi4")
|
||||||
@ -1493,8 +1515,9 @@ func (b *LocalBackend) initPeerAPIListener() {
|
|||||||
|
|
||||||
var tunName string
|
var tunName string
|
||||||
if ge, ok := b.e.(wgengine.InternalsGetter); ok {
|
if ge, ok := b.e.(wgengine.InternalsGetter); ok {
|
||||||
tunDev, _ := ge.GetInternals()
|
if tunWrap, _, ok := ge.GetInternals(); ok {
|
||||||
tunName, _ = tunDev.Name()
|
tunName, _ = tunWrap.Name()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ps := &peerAPIServer{
|
ps := &peerAPIServer{
|
||||||
|
@ -418,6 +418,11 @@ type PingResult struct {
|
|||||||
// It is not currently set for TSMP pings.
|
// It is not currently set for TSMP pings.
|
||||||
DERPRegionCode string
|
DERPRegionCode string
|
||||||
|
|
||||||
|
// PeerAPIPort is set by TSMP ping responses for peers that
|
||||||
|
// are running a peerapi server. This is the port they're
|
||||||
|
// running the server on.
|
||||||
|
PeerAPIPort uint16 `json:",omitempty"`
|
||||||
|
|
||||||
// TODO(bradfitz): details like whether port mapping was used on either side? (Once supported)
|
// TODO(bradfitz): details like whether port mapping was used on either side? (Once supported)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,11 +224,14 @@ func (pp *Parsed) AsTSMPPing() (h TSMPPingRequest, ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TSMPPongReply struct {
|
type TSMPPongReply struct {
|
||||||
IPHeader Header
|
IPHeader Header
|
||||||
Data [8]byte
|
Data [8]byte
|
||||||
|
PeerAPIPort uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *Parsed) AsTSMPPong() (data [8]byte, ok bool) {
|
// 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 {
|
if pp.IPProto != ipproto.TSMP {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -236,12 +239,15 @@ func (pp *Parsed) AsTSMPPong() (data [8]byte, ok bool) {
|
|||||||
if len(p) < 9 || p[0] != byte(TSMPTypePong) {
|
if len(p) < 9 || p[0] != byte(TSMPTypePong) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(data[:], p[1:])
|
copy(pong.Data[:], p[1:])
|
||||||
return data, true
|
if len(p) >= 11 {
|
||||||
|
pong.PeerAPIPort = binary.BigEndian.Uint16(p[9:])
|
||||||
|
}
|
||||||
|
return pong, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h TSMPPongReply) Len() int {
|
func (h TSMPPongReply) Len() int {
|
||||||
return h.IPHeader.Len() + 9
|
return h.IPHeader.Len() + 11
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h TSMPPongReply) Marshal(buf []byte) error {
|
func (h TSMPPongReply) Marshal(buf []byte) error {
|
||||||
@ -254,5 +260,6 @@ func (h TSMPPongReply) Marshal(buf []byte) error {
|
|||||||
buf = buf[h.IPHeader.Len():]
|
buf = buf[h.IPHeader.Len():]
|
||||||
buf[0] = byte(TSMPTypePong)
|
buf[0] = byte(TSMPTypePong)
|
||||||
copy(buf[1:], h.Data[:])
|
copy(buf[1:], h.Data[:])
|
||||||
|
binary.BigEndian.PutUint16(buf[9:11], h.PeerAPIPort)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,11 @@ type Wrapper struct {
|
|||||||
PostFilterOut FilterFunc
|
PostFilterOut FilterFunc
|
||||||
|
|
||||||
// OnTSMPPongReceived, if non-nil, is called whenever a TSMP pong arrives.
|
// OnTSMPPongReceived, if non-nil, is called whenever a TSMP pong arrives.
|
||||||
OnTSMPPongReceived func(data [8]byte)
|
OnTSMPPongReceived func(packet.TSMPPongReply)
|
||||||
|
|
||||||
|
// PeerAPIPort, if non-nil, returns the peerapi port that's
|
||||||
|
// running for the given IP address.
|
||||||
|
PeerAPIPort func(netaddr.IP) (port uint16, ok bool)
|
||||||
|
|
||||||
// disableFilter disables all filtering when set. This should only be used in tests.
|
// disableFilter disables all filtering when set. This should only be used in tests.
|
||||||
disableFilter bool
|
disableFilter bool
|
||||||
@ -456,6 +460,9 @@ func (t *Wrapper) injectOutboundPong(pp *packet.Parsed, req packet.TSMPPingReque
|
|||||||
pong := packet.TSMPPongReply{
|
pong := packet.TSMPPongReply{
|
||||||
Data: req.Data,
|
Data: req.Data,
|
||||||
}
|
}
|
||||||
|
if t.PeerAPIPort != nil {
|
||||||
|
pong.PeerAPIPort, _ = t.PeerAPIPort(pp.Dst.IP)
|
||||||
|
}
|
||||||
switch pp.IPVersion {
|
switch pp.IPVersion {
|
||||||
case 4:
|
case 4:
|
||||||
h4 := pp.IP4Header()
|
h4 := pp.IP4Header()
|
||||||
|
@ -116,19 +116,19 @@ type userspaceEngine struct {
|
|||||||
pingers map[wgkey.Key]*pinger // legacy pingers for pre-discovery peers
|
pingers map[wgkey.Key]*pinger // legacy pingers for pre-discovery peers
|
||||||
pendOpen map[flowtrack.Tuple]*pendingOpenFlow // see pendopen.go
|
pendOpen map[flowtrack.Tuple]*pendingOpenFlow // see pendopen.go
|
||||||
networkMapCallbacks map[*someHandle]NetworkMapCallback
|
networkMapCallbacks map[*someHandle]NetworkMapCallback
|
||||||
tsIPByIPPort map[netaddr.IPPort]netaddr.IP // allows registration of IP:ports as belonging to a certain Tailscale IP for whois lookups
|
tsIPByIPPort map[netaddr.IPPort]netaddr.IP // allows registration of IP:ports as belonging to a certain Tailscale IP for whois lookups
|
||||||
pongCallback map[[8]byte]func() // for TSMP pong responses
|
pongCallback map[[8]byte]func(packet.TSMPPongReply) // for TSMP pong responses
|
||||||
|
|
||||||
// Lock ordering: magicsock.Conn.mu, wgLock, then mu.
|
// Lock ordering: magicsock.Conn.mu, wgLock, then mu.
|
||||||
}
|
}
|
||||||
|
|
||||||
// InternalsGetter is implemented by Engines that can export their internals.
|
// InternalsGetter is implemented by Engines that can export their internals.
|
||||||
type InternalsGetter interface {
|
type InternalsGetter interface {
|
||||||
GetInternals() (*tstun.Wrapper, *magicsock.Conn)
|
GetInternals() (_ *tstun.Wrapper, _ *magicsock.Conn, ok bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *userspaceEngine) GetInternals() (*tstun.Wrapper, *magicsock.Conn) {
|
func (e *userspaceEngine) GetInternals() (_ *tstun.Wrapper, _ *magicsock.Conn, ok bool) {
|
||||||
return e.tundev, e.magicConn
|
return e.tundev, e.magicConn, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config is the engine configuration.
|
// Config is the engine configuration.
|
||||||
@ -310,13 +310,13 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
|||||||
SkipBindUpdate: true,
|
SkipBindUpdate: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
e.tundev.OnTSMPPongReceived = func(data [8]byte) {
|
e.tundev.OnTSMPPongReceived = func(pong packet.TSMPPongReply) {
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
defer e.mu.Unlock()
|
defer e.mu.Unlock()
|
||||||
cb := e.pongCallback[data]
|
cb := e.pongCallback[pong.Data]
|
||||||
e.logf("wgengine: got TSMP pong %02x; cb=%v", data, cb != nil)
|
e.logf("wgengine: got TSMP pong %02x, peerAPIPort=%v; cb=%v", pong.Data, pong.PeerAPIPort, cb != nil)
|
||||||
if cb != nil {
|
if cb != nil {
|
||||||
go cb()
|
go cb(pong)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1389,12 +1389,13 @@ func (e *userspaceEngine) sendTSMPPing(ip netaddr.IP, peer *tailcfg.Node, res *i
|
|||||||
e.setTSMPPongCallback(data, nil)
|
e.setTSMPPongCallback(data, nil)
|
||||||
})
|
})
|
||||||
t0 := time.Now()
|
t0 := time.Now()
|
||||||
e.setTSMPPongCallback(data, func() {
|
e.setTSMPPongCallback(data, func(pong packet.TSMPPongReply) {
|
||||||
expireTimer.Stop()
|
expireTimer.Stop()
|
||||||
d := time.Since(t0)
|
d := time.Since(t0)
|
||||||
res.LatencySeconds = d.Seconds()
|
res.LatencySeconds = d.Seconds()
|
||||||
res.NodeIP = ip.String()
|
res.NodeIP = ip.String()
|
||||||
res.NodeName = peer.ComputedName
|
res.NodeName = peer.ComputedName
|
||||||
|
res.PeerAPIPort = pong.PeerAPIPort
|
||||||
cb(res)
|
cb(res)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1406,11 +1407,11 @@ func (e *userspaceEngine) sendTSMPPing(ip netaddr.IP, peer *tailcfg.Node, res *i
|
|||||||
e.tundev.InjectOutbound(tsmpPing)
|
e.tundev.InjectOutbound(tsmpPing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *userspaceEngine) setTSMPPongCallback(data [8]byte, cb func()) {
|
func (e *userspaceEngine) setTSMPPongCallback(data [8]byte, cb func(packet.TSMPPongReply)) {
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
defer e.mu.Unlock()
|
defer e.mu.Unlock()
|
||||||
if e.pongCallback == nil {
|
if e.pongCallback == nil {
|
||||||
e.pongCallback = map[[8]byte]func(){}
|
e.pongCallback = map[[8]byte]func(packet.TSMPPongReply){}
|
||||||
}
|
}
|
||||||
if cb == nil {
|
if cb == nil {
|
||||||
delete(e.pongCallback, data)
|
delete(e.pongCallback, data)
|
||||||
|
@ -15,9 +15,11 @@ import (
|
|||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
"tailscale.com/ipn/ipnstate"
|
"tailscale.com/ipn/ipnstate"
|
||||||
"tailscale.com/net/dns"
|
"tailscale.com/net/dns"
|
||||||
|
"tailscale.com/net/tstun"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/netmap"
|
"tailscale.com/types/netmap"
|
||||||
"tailscale.com/wgengine/filter"
|
"tailscale.com/wgengine/filter"
|
||||||
|
"tailscale.com/wgengine/magicsock"
|
||||||
"tailscale.com/wgengine/monitor"
|
"tailscale.com/wgengine/monitor"
|
||||||
"tailscale.com/wgengine/router"
|
"tailscale.com/wgengine/router"
|
||||||
"tailscale.com/wgengine/wgcfg"
|
"tailscale.com/wgengine/wgcfg"
|
||||||
@ -133,6 +135,12 @@ func (e *watchdogEngine) WhoIsIPPort(ipp netaddr.IPPort) (tsIP netaddr.IP, ok bo
|
|||||||
func (e *watchdogEngine) Close() {
|
func (e *watchdogEngine) Close() {
|
||||||
e.watchdog("Close", e.wrap.Close)
|
e.watchdog("Close", e.wrap.Close)
|
||||||
}
|
}
|
||||||
|
func (e *watchdogEngine) GetInternals() (tw *tstun.Wrapper, c *magicsock.Conn, ok bool) {
|
||||||
|
if ig, ok := e.wrap.(InternalsGetter); ok {
|
||||||
|
return ig.GetInternals()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
func (e *watchdogEngine) Wait() {
|
func (e *watchdogEngine) Wait() {
|
||||||
e.wrap.Wait()
|
e.wrap.Wait()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user