mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-04 15:35:38 +00:00
disco, wgengine/magicsock: send self node key in disco pings
This lets clients quickly (sub-millisecond within a local LAN) map
from an ambiguous disco key to a node key without waiting for a
CallMeMaybe (over relatively high latency DERP).
Updates #3088
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
(cherry picked from commit 75a7779b42
)
This commit is contained in:
parent
76ad9d7a7a
commit
ac4cda9303
@ -26,6 +26,7 @@
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Magic is the 6 byte header of all discovery messages.
|
// Magic is the 6 byte header of all discovery messages.
|
||||||
@ -106,12 +107,28 @@ func appendMsgHeader(b []byte, t MessageType, ver uint8, dataLen int) (all, data
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Ping struct {
|
type Ping struct {
|
||||||
|
// TxID is a random client-generated per-ping transaction ID.
|
||||||
TxID [12]byte
|
TxID [12]byte
|
||||||
|
|
||||||
|
// NodeKey is the ping sender's wireguard public key. Old
|
||||||
|
// clients (~1.16.0 and earlier) don't send this field. It
|
||||||
|
// shouldn't be trusted by itself. But if present and the
|
||||||
|
// netmap's peer for this NodeKey's DiscoKey matches the
|
||||||
|
// sender of this disco key, they it can be.
|
||||||
|
NodeKey tailcfg.NodeKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Ping) AppendMarshal(b []byte) []byte {
|
func (m *Ping) AppendMarshal(b []byte) []byte {
|
||||||
ret, d := appendMsgHeader(b, TypePing, v0, 12)
|
dataLen := 12
|
||||||
copy(d, m.TxID[:])
|
hasKey := !m.NodeKey.IsZero()
|
||||||
|
if hasKey {
|
||||||
|
dataLen += len(m.NodeKey)
|
||||||
|
}
|
||||||
|
ret, d := appendMsgHeader(b, TypePing, v0, dataLen)
|
||||||
|
n := copy(d, m.TxID[:])
|
||||||
|
if hasKey {
|
||||||
|
copy(d[n:], m.NodeKey[:])
|
||||||
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +137,10 @@ func parsePing(ver uint8, p []byte) (m *Ping, err error) {
|
|||||||
return nil, errShort
|
return nil, errShort
|
||||||
}
|
}
|
||||||
m = new(Ping)
|
m = new(Ping)
|
||||||
copy(m.TxID[:], p)
|
p = p[copy(m.TxID[:], p):]
|
||||||
|
if len(p) >= len(m.NodeKey) {
|
||||||
|
copy(m.NodeKey[:], p)
|
||||||
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMarshalAndParse(t *testing.T) {
|
func TestMarshalAndParse(t *testing.T) {
|
||||||
@ -26,6 +27,19 @@ func TestMarshalAndParse(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: "01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c",
|
want: "01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ping_with_nodekey_src",
|
||||||
|
m: &Ping{
|
||||||
|
TxID: [12]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
|
||||||
|
NodeKey: tailcfg.NodeKey{
|
||||||
|
1: 1,
|
||||||
|
2: 2,
|
||||||
|
30: 30,
|
||||||
|
31: 31,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: "01 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 00 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1e 1f",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "pong",
|
name: "pong",
|
||||||
m: &Pong{
|
m: &Pong{
|
||||||
|
@ -281,7 +281,8 @@ type Conn struct {
|
|||||||
networkUp syncs.AtomicBool
|
networkUp syncs.AtomicBool
|
||||||
|
|
||||||
// havePrivateKey is whether privateKey is non-zero.
|
// havePrivateKey is whether privateKey is non-zero.
|
||||||
havePrivateKey syncs.AtomicBool
|
havePrivateKey syncs.AtomicBool
|
||||||
|
publicKeyAtomic atomic.Value // of tailcfg.NodeKey (or NodeKey zero value if !havePrivateKey)
|
||||||
|
|
||||||
// port is the preferred port from opts.Port; 0 means auto.
|
// port is the preferred port from opts.Port; 0 means auto.
|
||||||
port syncs.AtomicUint32
|
port syncs.AtomicUint32
|
||||||
@ -2053,6 +2054,12 @@ func (c *Conn) SetPrivateKey(privateKey wgkey.Private) error {
|
|||||||
c.privateKey = newKey
|
c.privateKey = newKey
|
||||||
c.havePrivateKey.Set(!newKey.IsZero())
|
c.havePrivateKey.Set(!newKey.IsZero())
|
||||||
|
|
||||||
|
if newKey.IsZero() {
|
||||||
|
c.publicKeyAtomic.Store(tailcfg.NodeKey{})
|
||||||
|
} else {
|
||||||
|
c.publicKeyAtomic.Store(tailcfg.NodeKey(newKey.Public()))
|
||||||
|
}
|
||||||
|
|
||||||
if oldKey.IsZero() {
|
if oldKey.IsZero() {
|
||||||
c.everHadKey = true
|
c.everHadKey = true
|
||||||
c.logf("magicsock: SetPrivateKey called (init)")
|
c.logf("magicsock: SetPrivateKey called (init)")
|
||||||
@ -3401,7 +3408,11 @@ func (de *endpoint) removeSentPingLocked(txid stun.TxID, sp sentPing) {
|
|||||||
// The caller (startPingLocked) should've already been recorded the ping in
|
// The caller (startPingLocked) should've already been recorded the ping in
|
||||||
// sentPing and set up the timer.
|
// sentPing and set up the timer.
|
||||||
func (de *endpoint) sendDiscoPing(ep netaddr.IPPort, txid stun.TxID, logLevel discoLogLevel) {
|
func (de *endpoint) sendDiscoPing(ep netaddr.IPPort, txid stun.TxID, logLevel discoLogLevel) {
|
||||||
sent, _ := de.sendDiscoMessage(ep, &disco.Ping{TxID: [12]byte(txid)}, logLevel)
|
selfPubKey, _ := de.c.publicKeyAtomic.Load().(tailcfg.NodeKey)
|
||||||
|
sent, _ := de.sendDiscoMessage(ep, &disco.Ping{
|
||||||
|
TxID: [12]byte(txid),
|
||||||
|
NodeKey: selfPubKey,
|
||||||
|
}, logLevel)
|
||||||
if !sent {
|
if !sent {
|
||||||
de.forgetPing(txid)
|
de.forgetPing(txid)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user